-
我们需要每次创建一个全新的Vue APP
node在使用renderer返回服务端渲染过的html的时候,将会传入一个app,这个app我们之前是在node程序中提前创建好的,这将导致很多问题
const app = new Vue({ ... })
app.get('*', (req, res) => {
renderer.renderToString(app, (err, html) => {
...
})
}
有没有发现,无论是谁来请求这个文件,传入的其实是app,这个app被所有人给共享了。这是非常不好的,如果王麻子请求页面的时候对app做了修改,那么之后的人去请求页面,都将收到一定的影响。我们需要避免状态单例。
因此,我们不应该直接创建一个应用程序实例,而是应该暴露一个可以重复执行的工厂函数,为每个请求创建新的应用程序实例:
// app.js
const Vue = require('vue')
module.exports = function createApp (context) {
return new Vue({
data: {
url: context.url
},
template: `<div>访问的 URL 是: {{ url }}</div>`
})
}
// server.js
const createApp = require('./app')
app.get('*', (req, res) => {
const app = createApp({ url: req.url })
renderer.renderToString(app, (err, html) => {
// 处理错误……
res.end(html)
})
})
同样的规则也适用于 router、store 和 event bus 实例。
了解以上的知识点后我们来看看如何同webpack同时构建出两个版本供给使用。
我们知道预渲染是需要一个Vue实例,而客户端其实也是需要一个Vue实例。我们往往需要做一些差异化的处理。
// 我们在普通编写单页应用的时候会在main.js中直接挂载
// 我们知道这是基于webpack 的写法
new Vue({
router,
store,
render: h => h(App),
}).$mount('#app')
// 我们需要的是两个app实例,一个是给服务端渲染用的,一个是给客户端用的,所以我们便将main.js改造一下,让其变成
export function createApp () {
const app = new Vue({
// 根实例简单的渲染应用程序组件。
render: h => h(App)
})
return { app }
}
// 会发现其是便成了创建实例的方法函数
// 我们在需要在客户端使用的时候,单纯的创建实例,挂载就好了
import { createApp } from './app'
const { app } = createApp()
app.$mount('#app')
// 在服务器渲染的时候,需要处理一下app实例
import { createApp } from './app'
export default context => {
const { app } = createApp()
return app
}