Vapper 是一个基于 Vue 的服务端渲染(SSR)框架,它的核心目标是:简
单、灵活、强大。
简单:尽最大的努力让开发 SSR 应用与开发 SPA 应用保持一致的体验,降>低学习成本和不同项目间切换的成本。最典型的例子是 Vapper 提供的数据>预取方案。
灵活:灵活体现在很多方面,例如 Vapper 只负责必要的 webpack 配置,这使得它可以配合 Vue-CLI、Poi 等优秀的工具一起使用;同时 Vapper 允许你在路由级别上控制是否开启 SSR、SPA 或预渲染的能力,这意味着同一个项目中不同的路由可能采用不同的处理方式。
强大:Vapper 的核心非常简单,但它的插件架构,让你拥有“渐进式”的增强能力,通过不同的插件对 Vapper 进行扩展,几乎能做到任何你期望的事情。实际上,Vapper 的许多核心功能也是以插件的方式实现的。
Vue 创建新项目
如果你还不会使用 vue-cli4 创建项目请参考这篇文章
vue create my-vapper-app
@vapper/configer-vue-cli
这是 Vapper 默认的 Configer,它会读取当前项目下安装的 @vue/cli-service 并使用它解析出相应的 Webpack 配置。因此 Vapper 可以与 Vue CLI 一同使用,这么做的好处是双向的:Vapper 拥有了全部 Vue CLI 的能力,同时 Vapper 为 Vue CLI 提供了服务端渲染的能力。
@vapper/configer-poi
Poi 也是一个优秀的 Webpack 管理工具,如果你的项目使用 Poi,将很容易接入 Vapper
@vapper/plugin-prerender - 预渲染 html
插件是框架级插件,提供了预渲染能力,指定需要预渲染的路由,该插件会把匹配的路由渲染为相应的 html 文件,当请求到来时,如果匹配指定的路由,则将已经预渲染完成的 html 文件作为静态资源发送给客户端。
@vapper/plugin-cookie - 服务器、客户端 cookie 共用
扩展了 Vapper 应用的运行时,在 Context 对象上添加了 $cookie 属性,用于同构操作
@vapper/plugin-platform
该插件会在 Context 对象和组件实例上注入 b r o w s e r 对 象 , 该 对 象 包 含 了 用 户 代 理 的 信 息 b r o w s e r s 选 项 是 一 个 数 组 , 因 此 可 以 定 义 多 条 规 则 。 如 上 高 亮 代 码 所 示 , 每 条 自 定 义 规 则 都 是 一 个 包 含 t e s t 属 性 和 d e s c r i b e 属 性 对 象 , 其 中 t e s t 属 性 是 一 个 数 组 , 指 定 一 组 匹 配 规 则 , 这 组 规 则 将 用 于 U A 字 符 串 , 一 旦 规 则 匹 配 , 将 会 执 行 d e s c r i b e 函 数 , 实 际 上 d e s c r i b e 函 数 的 返 回 值 可 以 通 过 t h i s . browser 对象,该对象包含了用户代理的信息browsers选项是一个数组,因此可以定义多条规则。如上高亮代码所示,每条自定义规则都是一个包含 test 属性和 describe 属性对象,其中 test 属性是一个数组,指定一组匹配规则,这组规则将用于 UA 字符串,一旦规则匹配,将会执行 describe 函数,实际上 describe 函数的返回值可以通过 this. browser对象,该对象包含了用户代理的信息browsers选项是一个数组,因此可以定义多条规则。如上高亮代码所示,每条自定义规则都是一个包含test属性和describe属性对象,其中test属性是一个数组,指定一组匹配规则,这组规则将用于UA字符串,一旦规则匹配,将会执行describe函数,实际上describe函数的返回值可以通过this.browser 访问在组件中使用 this.$browser.isChrome() // true or false
npm install @vapper/core
npm install vue-template-compiler
npm install @vapper/configer-vue-cli -D
npm install @vapper/configer-poi -D
//可选插件
npm install @vapper/plugin-prerender
npm install @vapper/plugin-cookie
npm install @vapper/plugin-platform
修改 package.json
“scripts”: {
“dev”: “vapper dev”,
“build”: “vapper build”,
“start”: “vapper start”
}
创建 vapper.config.js
Vapper 会寻找项目根目录中的 vapper.config.js 文件,并加载该文件导出的对象作为配置选项
const fs = require('fs');
const path = require('path');
/*导入自定义插件
* 插件可以是一个函数:*/
// const myVapperPlugin = require(path.resolve(__dirname, './src/plugins/myVapperPlugin.js'));
module.exports = {
/*入口文件 默认 main.js*/
// entry:require(path.resolve(__dirname,'./src/vapper.main.js')),
mode: 'development',
/*自定义html 模板*/
// template: fs.readFileSync(path.resolve(__dirname, './src/templates/default.html'), 'utf-8'),
/*指定端口号*/
port: 4000,
host: '127.0.0.1',
// 自定义 logger
/*设置日志级别*/
/*logLevel === 0 ----> silent
logLevel === 1 ----> error
logLevel === 2 ----> error/warn
logLevel === 3 ----> error/warn/debug
logLevel === 4 ----> error/warn/debug/tip
logLevel === 5 ----> error/warn/debug/tip/info*/
logLevel: 5,
logger(...args) {
console.log(...args)
},
plugins: [
// [myVapperPlugin],
[
'@vapper/plugin-prerender',
{
routes: ['/foo']
}, "scripts", {
"generate": "vapper generate"
}
],
['@vapper/plugin-cookie'],
[
'@vapper/plugin-platform',
{
browsers: [
// 自定义 UA 检测规则
{
test: [/chrome/],
describe(ua) {
const browser = {
name: 'SupperChrome'
}
return browser
}
},
]
}
]
],
// 允许压缩服务端渲染的 html 内容
htmlMinifier: true,
// 当错误发生时是否回退 SPA 模式,默认为 true,即回退 SPA 模式
fallBackSpa:
true,
// 指定 Server Bundle 的文件名 serverBundleFileName:
// 默认值:'vue-ssr-client-manifest.json'
//clientManifestFileName
// 默认值:'vue-ssr-client-manifest.json'
// 指定 Client Manifest 的文件名
//设置页面级缓存 只有“用户无关的动态资源”适合应用 共用资源
pageCache:
{
cacheable: req => req.url === '/about',
getCacheKey:
req => req.url + new Date()
}
,
}
修改 main.js 文件
import Vue from 'vue'
import VueRouter from 'vue-router'
import App from './App.vue'
Vue.config.productionTip = false
Vue.use(VueRouter)
// Export factory function
export default function createApp () {
// 1. Create a router instance
const router = new VueRouter({
mode: 'history',
routes: [
{
path: '/',
component: () => import('./components/HelloWorld.vue'),
meta: {
ssr: true
}
}
]
})
// 2. Create the root component option
const app = {
router,
// This is necessary, it is for vue-meta
head: {},
render: h => h(App)
}
// 3. return
return app
}
删除 router 文件及其子文件夹
访问 localhost:4000