https://github.com/zhengchao627/vue-ssr 郑超组配的ssr
https://github.com/conan2008/growup 张元组配的ssr
vue ssr的问题总结
vue与vue-server-renderer的版本必须一致,否则会报错:
2.模板中必须要加入
该注释是vue-ssr的默认内容注入入口,相关源码如下:
默认是使用该注释作为注入入口,如果没有添加该注释,就会报错 'Content placeholder not found in template'
而且做了兼容,如果没有找到</head>标签,就会找到<body>标签,如果还是没找到,就会用 所在位置3.生命周期
由于没有动态更新,所有的生命周期钩子函数中,只有 beforeCreate 和 created 会在服务器端渲染(SSR)过程中被调用。这就是说任何其他生命周期钩子函数中的代码(例如 beforeMount 或 mounted),只会在客户端执行。
此外还需要注意的是,你应该避免在 beforeCreate 和 created 生命周期时产生全局副作用的代码,例如在其中使用 setInterval 设置 timer。在纯客户端(client-side only)的代码中,我们可以设置一个 timer,然后在 beforeDestroy或 destroyed 生命周期时将其销毁。但是,由于在 SSR 期间并不会调用销毁钩子函数,所以 timer 将永远保留下来。为了避免这种情况,请将副作用代码移动到 beforeMount 或 mounted 生命周期中。4.模板插值
模板还支持简单插值。给定如下模板:
<html>
<head>
<!-- 使用双花括号(double-mustache)进行 HTML 转义插值(HTML-escaped interpolation) 即如果传入<span>xxx</span> 则<和>这些符号会被转义 -->
<title>{{ title }}</title>
<!-- 使用三花括号(triple-mustache)进行 HTML 不转义插值(non-HTML-escaped interpolation) -->
{{{ meta }}}
</head>
<body>
<!--vue-ssr-outlet-->
</body>
</html>
我们可以通过传入一个"渲染上下文对象",作为 renderToString 函数的第二个参数,来提供插值数据:
const context = {
title: 'hello',
meta: `
<meta ...>
<meta ...>
`
}
renderer.renderToString(app, context, (err, html) => {
// page title will be "Hello"
// with meta tags injected
})
5.不可使用全局环境变量
因为代码会运行在node环境中,所以注意不要使用window或者document等依赖浏览器环境的环境变量
6.避免状态单例
当编写纯客户端(client-only)代码时,我们习惯于每次在新的上下文>中对代码进行取值。但是,Node.js 服务器是一个长期运行的进程。>当我们的代码进入该进程时,它将进行一次取值并留存在内存中。这
意味着如果创建一个单例对象,它将在每个传入的请求之间共享。
如果我们在多个请求之间使用一个共享的实例,很容易导致交叉请求状态污染(cross-request state pollution)。
因此,我们不应该直接创建一个应用程序实例,而是应该暴露一个可以重复执行的工厂函数,为每个请求创建新的应用程序实例:
// 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')
server.get('*', (req, res) => {
const context = { url: req.url }
const app = createApp(context)
renderer.renderToString(app, (err, html) => {
// 处理错误……
res.end(html)
})
})
同样的规则也适用于 router、store 和 event bus 实例。你不应该直接从模块导出并将其导入到应用程序中,而是需要在 createApp 中创建一个新的实例,并从根 Vue 实例注入。
7.renderToString的注意点
如果在renderer创建的时候就传入了template,如下:
var renderer = serverRender.createRenderer({
template: require('fs').readFileSync(path.resolve(__dirname, '../index.ssr.html'), 'utf-8')
})
8.异步加载组件
在 Vue 2.5 以下的版本中,服务端渲染时异步组件只能用在路由组件上。然而在 2.5+ 的版本中,得益于核心算法的升级,异步组件现在可以在应用中的任何地方使用。
需要注意的是,你任然需要在挂载 app 之前调用 router.onReady,因为路由器必须要提前解析路由配置中的异步组件,才能正确地调用组件中可能存在的路由钩子。
9.状态处理
获取的数据需要位于视图组件之外,即放置在专门的数据预取存储容器(data store)或"状态容器(state container))"中。首先,在服务器端,我们可以在渲染之前预取数据,并将数据填充到 store 中。此外,我们将在 HTML 中序列化(serialize)和内联预置(inline)状态。这样,在挂载(mount)到客户端应用程序之前,可以直接从 store 获取到内联预置(inline)状态。
10.ssr的热加载
vue-server-renderer 提供一个名为 createBundleRenderer 的 API,用于处理此问题,通过使用 webpack 的自定义插件,server bundle 将生成为可传递到 bundle renderer 的特殊 JSON 文件。所创建的 bundle renderer,用法和普通 renderer 相同,但是 bundle renderer 提供以下优点:
- 内置的 source map 支持(在 webpack 配置中使用 devtool: 'source-map')
- 在开发环境甚至部署过程中热重载(通过读取更新后的 bundle,然后重新创建 renderer 实例)
- 关键 CSS(critical CSS) 注入(在使用 *.vue 文件时):自动内联在渲染过程中用到的组件所需的CSS。更多细节请查看 CSS 章节。
- 使用 clientManifest 进行资源注入:自动推断出最佳的预加载(preload)和预取(prefetch)指令,以及初始渲染所需的代码分割 chunk。
11.Webpack中打包的注意点:
有些属性需要指定: 如target为node,libraryTarget为commonjs2等
在源码中对应,(因为在源码中会检查这些项目)