服务端渲染简而言之就是将本来要放在浏览器执行创建的组件,放到服务端先创建好,然后生成对应的html将它们直接发送到浏览器,最后将这些静态标记"激活"为客户端上完全可交互的应用程序。
Vue SSR 相比 SPA(单页应用)优缺点:
优点:
- 更好的 SEO,由于搜索引擎爬虫抓取工具可以直接查看完全渲染的页面。
- 更快的内容到达时间(time-to-content),特别是对于缓慢的网络情况或运行缓慢的设备。
缺点:
- 开发条件所限。浏览器特定的代码,只能在某些生命周期钩子函数(lifecycle hook)中使用,一些外部扩展库(external library)可能需要特殊处理,才能在服务器渲染应用程序中运行。
- 涉及构建设置和部署的更多要求。与可以部署在任何静态文件服务器上的完全静态单页面应用程序(SPA)不同,服务器渲染应用程序,需要处于 Node.js server 运行环境。
- 更多的服务器端负载。在 Node.js 中渲染完整的应用程序,显然会比仅仅提供静态文件的 server 更加大量占用 CPU 资源(CPU-intensive - CPU 密集),因此如果你预料在高流量环境(high traffic)下使用,请准备相应的服务器负载,并明智地采用缓存策略。
接下来让我们看看单页面应用网站与服务端渲染网站的区别,使用chrome浏览器分别打开两个网站,右击查看源码。
单页面应用网站
服务端渲染
可以明显看出改版后网站源码增加了不止几倍之多,简而言之服务端渲染的模式就是:在请求一个网址的时候,服务端收到请求之后把html的内容先生成好然后再返回给浏览器。这样子搜索引擎就可以通过你返回的a标签抓取到网站的其他页面了,依此类推搜索引擎就可以收录网站的所有(暴露出来的)路径了。
让我们动手实现一个Vue SSR实例
- 创建一个空项目 mkdir vuessr && cd vuessr
- 运行 yarn init 进行初始化
- 安装我们需要的依赖
yarn add vue vue-server-renderer --save
- 创建index.js代码如下:
// 第 1 步:创建一个 Vue 实例
const Vue = require('vue')
const app = new Vue({
template: `<div>Hello World</div>`
})
// 第 2 步:创建一个 renderer
const renderer = require('vue-server-renderer').createRenderer()
// 第 3 步:将 Vue 实例渲染为 HTML
renderer.renderToString(app, (err, html) => {
if (err) throw err
console.log(html)
// => <div data-server-rendered="true">Hello World</div>
})
- 运行 node index.js 可以看到在控制台输出了
<div data-server-rendered="true">Hello World</div>
- 安装依赖
yarn add express --save
- 创建app.js代码如下:
const Vue = require('vue')
const server = require('express')()
const renderer = require('vue-server-renderer').createRenderer()
server.get('*', (req, res) => {
const app = new Vue({
data: {
url: req.url
},
template: `<div>访问的 URL 是:{{ url }}</div>`
})
renderer.renderToString(app, (err, html) => {
if (err) {
res.status(500).end('Internal Server Error')
return
}
res.end(`
<!DOCTYPE html>
<html lang="en">
<head><title>Hello</title></head>
<body>${html}</body>
</html>
`)
})
})
server.listen(8080)
运行node app.js
打开浏览器输入http://localhost:8080/发现我们的内容已经显示出来了,如果有同学发现有中文乱码的问题,可以设置一下编码:
renderer.renderToString(app, (err, html) => {
if (err) {
res.status(500).end('Internal Server Error')
return
}
//设置编码
res.writeHead(200, {'Content-Type':'text/html;charset=utf-8'});
res.end(`
<!DOCTYPE html>
<html lang="zh">
<head><title>Hello</title></head>
<body>${html}</body>
</html>
`)
})
到此为止我们已经实现一个最基础的vue 服务端渲染的工程了。是不是很简单?不过要从头搭建整套Vue SSR还是一个非常繁琐的过程。
下面以官方的SSR服务器端渲染流程图为例,进行概要说明
- universal Application Code是服务器端和浏览器端通用的代码。
- app.js是应用程序的入口entry,对应vue cli生成项目的main.js文件。
- entry-client.js是客户端入口,仅运行于浏览器,entry-server.js是服务器端入口,仅运行于服务器。
- entry-client和entry-server这两个文件都需要通过webpack构建,其中entry-client需要通过webpack.client.config.js文件打包,entry-server需要通过webpack.server.config.js文件打包。
- entry-client构建后的client Bundle打包文件是vue-ssr-client-manifest.json,entry-server构建后的server Bundle打包文件是vue-ssr-server-bundle.json
- server.js文件将客户端打包文件vue-ssr-client-manifest.json、服务器端打包文件vue-ssr-server-bundle.json和HTML模板混合,渲染成HTML。
具体怎么改造现有项目为服务端渲染可以参考这篇文章 基于vue现有项目的服务器端渲染SSR改造