服务端渲染(SSR)近两年炒得很火热,相信各位同学对这个名词多少有所耳闻,本节我们将围绕“是什么”(服务端渲染的运行机制)、“为什么”(服务端渲染解决了什么性能问题)、“怎么做”(服务端渲染的应用实例与使用场景)这三个点,对服务端渲染进行探索。 服务端渲染是一个相对的概念,它的对立面是“客户端渲染”。在运行机制解析方部分,我们会借力客户端渲染的概念,来帮大家理解服务端渲染的工作方式,基于对工作方式的了解,再去深挖它的原理与优势。 任务知识点都不是“一座孤岛”,服务端渲染的实践往往与当下流行的前端技术(譬如VUE,REACT REDUX 等)紧密结合,本节下半场将以REACT 和VUE下的服务端渲染实现为例,为大家呈现一个完整的SSR实现过程。 服务端渲染的运行机制 相对于服务端沉浸,同学们普遍对客户端渲染接受度更高一些,所以我们先从大家喜闻乐见的客户端渲染说起。 客户端渲染 客户关渲染模式下,服务端会把渲染需要的靜态文件发送给客户端,客户端加载过来之后,自己在浏览器里跑一遍JS,根据JS的运行结果,生成相应 的DOM,这种特性使得客户端渲染的源代码总是特别简洁,往往是这个德行: ``` <!doctype html> <html> <head> <title>我是客户端渲染的页面</title> </head> <body> <div id='root'></div> <script src='index.js'></script> </body> </html> ``` 根节点下到底是什么内容呢?你不知道,我不知道,只有浏览器把 index.js 跑过一遍后才知道,这就是典型的客户端渲染。 页面上呈现的内容,你在html源文件里找不到的--这正是它的特点 服务端渲染 服务端渲染的模式下,当用户第一次请求页面时,由服务器把需要的组件或页面渲染成HTML字符串,然后把它返回给客户端, 客户端拿到手的,是可以直接渲染然后呈现给用户的HTML内容,不需要为了生成DOM内容自己再去跑一遍JS代码。 使用服务端渲染的网站,可以说是“所见即所得”,页面上呈现的内容,我们在html源文件里也能找到。 服务端渲染解决了什么性能问题 事实上,很多网站是出于效益的考虑才启用服务端渲染,性能倒是在其次。 假设A网站页面中有一个关键字叫“前端性能优化”,这个关键字中JS 代码跑过一遍后添加到HMTL页面中的,那么客户端渲染模式下,我们在搜索引 擎搜索这个关键字,是找不到A网站的--搜索引擎只会查找现成的内容,不会帮你跑JS代码。A网站的运营方见此情形,感到很头大,搜索引擎搜不出来,用户找不到我们,谁还会用我的网站呢?为了把“现成的内容”拿给搜索引擎看,A网站不得不启用服务端渲染。 但性能在其次,不代表性能不重要,服务端渲染解决了一个非常关键的性能问题--首屏加载速度过慢。在客户端渲染模式下,我们除了加载HTML,还要等渲染所需要的这部分JS加载完,之后还得把这部分JS在浏览器上再跑一遍。这一切都是发生在用户点击了我们的链接之后的事情,在这个过程结束之前,用户始终见不到我们网页的庐山真面目,也就是说用户一直在等!相比之下,服务端渲染模式下,服务器给客户端的已经是一个直接可以拿来呈现给用户的网页,中间环节早在服务端就帮我们做掉了,用户岂不“美滋滋”? VUE实现思路 该示例直接将VUE实例整合进了服务端的入口文件中: ``` const Vue = require('vue') // 创建一个express 应用 const server = require('express')() // 提取出 render 实例 const renderer = require('vue-server-renderer').createRenderer() server.get('*',(req,res) => { // 编写VUE 实例 (虛拟DOM节点) const app = new Vue({ data:{ url: req.url }, template: `<div>访问的 url 是 {{ url }}</div>` }) // renderToString 是把 vue 实例转化为真实 dom 的关键方法 renderer.renderToString(app,(err,html) => { if(err){ res.status(500).end('Interal Server Error') return } // 把渲染出来的真实dom 字符串插入HTML模板中 res.end(` <!doctype html> <html lang="en"> <head><title>hello</title></head> <body>${html}</body> </html> `) }) }) ```