服务端渲染 客户端渲染 预渲染

三种渲染方式

客户端渲染:用户访问 url,请求 html 文件,前端根据路由动态渲染页面内容。关键链路较长,有一定的白屏时间;

服务端渲染:用户访问 url,服务端根据访问路径请求所需数据,拼接成 html 字符串,返回给前端。前端接收到 html 时已有部分内容;

预渲染构建阶段生成匹配预渲染路径的 html 文件(注意:每个需要预渲染的路由都有一个对应的 html)。构建出来的 html 文件已有部分内容。

客户端渲染

什么是客户端渲染

  1. http发起请求

  2. 服务端接受请求,响应一个页面index.html给客户端,也可以说是一个页面字符串。

  3. 客户端拿到页面,然后进行解析渲染,解析到静态页面会渲染显示在浏览器上,解析到script动态脚本<script src='user.js'></script>,则浏览器会再次向浏览器发起请求

  4. 服务端再次处理服务端的请求,然后响应数据

  5. 客户端拿到服务器返回的数据,然后利用模板引擎进行渲染,最终将数据也显示在页面上

优缺点

与服务端渲染相反

服务端渲染

什么是服务端渲染

服务器端的渲染,指的是客户端只需要发起一次http请求,服务器就会一次性将渲染好的页面进行返回,客户端不需要再次发起请求去服务器端拿数据。

优点

  • 首屏时间短

服务端在内网进行请求数据,响应速度快。客户端在不同网络环境进行数据请求,且外网http请求开销大。

服务器性能好,渲染更快。

  • 利于 SEO

因为后端会返回完整的 html 页面

  • 占用客户端资源少

移动端省电

缺点

  • 不利于前后端分离

后端在生成前端的页面

  • 占用服务器端资源

如果请求较多,会对服务器造成一定的访问压力

使用

vue框架的项目,使用nuxt就很方便了,我们只需要按照nuxt的脚手架创建好项目结构,然后就可以按照vue的开发方式进行开发了。
nuxt支持SSR服务端渲染模式和SSG静态生成模式,如果说我们的页面需要提前动态获取数据并进行拼接,我们就需要使用服务端渲染模式;如果说我们的页面静态的东西比较多,动态数据不需要考虑SEO,那么我们可以选择静态生成模式,相当于使用预渲染,不需要node服务器也能够提升SEO。

预渲染

什么是预渲染

SSG(static side generate),无需服务器实时动态编译,在构建时针对特定路由简单的生成静态HTML文件

预渲染的作用

针对单页应用,服务端渲染和预渲染共同解决的问题:

  1. SEO:单页应用的网站内容是根据当前路径动态渲染的,html 文件中往往没有内容,网络爬虫不会等到页面脚本执行完再抓取;
  2. 弱网环境:当用户在一个弱环境中访问你的站点时,你会想要尽可能快的将内容呈现给他们。甚至是在 js 脚本被加载和解析前;
  3. 低版本浏览器:用户的浏览器可能不支持你使用的 js 特性,预渲染或服务端渲染能够让用户至少能够看到首屏的内容,而不是一个空白的网页。

预渲染能与服务端渲染一样提高 SEO 优化,但前者比后者需要更少的配置,实现成本低。弱网环境下,预渲染能更快地呈现页面内容,减少页面可见时间。

不适合的场景

1.个性化内容:对于路由是 /my-profile 的页面来说,预渲染就失效了。因为页面内容依据看它的人而显得不同;

2.经常变化的内容:如果你预渲染一个游戏排行榜,这个排行榜会随着新的玩家记录而更新,预渲染会让你的页面显示不正确直到脚本加载完成并替换成新的数据。这是一个不好的用户体验;

3.成千上万的路由:不建议预渲染非常多的路由,因为这会严重拖慢你的构建进程。

使用预渲染

prerender-spa-plugin

prerender-spa-plugin 是一个 webpack 插件用于在单页应用中预渲染静态 html 内容。它是框架无关的。

预渲染的单页应用路由需要使用 History 模式而不是 Hash 模式。原因很简单,Hash 不会带到服务器,路由信息会丢失。

配置预渲染前

没有配置预渲染的话,一般来说,根据 nginx 的配置,无论访问哪个路由都会返回首页 dist/index.html。具体情况视配置而见

1
2
3
location / {
try_files $uri $uri/ /index.html;
}

配置预渲染

安装包

1
npm install prerender-spa-plugin

配置 webpack

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var path = require('path')
var PrerenderSpaPlugin = require('prerender-spa-plugin')

{
// ...
plugins: [
// ...
new PrerenderSpaPlugin(
// 输出目录的绝对路径
path.join(__dirname, '../dist'),
// 预渲染的路由
[ '/new', '/hot' ]
)
]
}

预渲染效果

1
2
3
4
5
6
7
8
9
10
dist
index.html

├─hot
index.html

├─new
index.html

└─static

对比 dist 目录,可以发现预渲染的目录多了两个文件 new/index.html, hot/index.html

其中,**/new** 和 /hot 路由返回的 html 包含了对应路由的内容,从而实现预渲染。进入这两个路由时,直接发请求获取预渲染的 html。

没有配置预渲染的路由跟原来一样,还是访问 /index.html,请求脚本,动态渲染。

预渲染达到了类似服务端渲染的效果。区别在于预渲染发生在构建时,服务端渲染发生在服务器处理请求时

总结

简单的说就是在 build 时会在 dist 文件夹里多生成几个 html 文件,数量根据需要预渲染的路由个数而变(webpack中配置)。进入路由时,会直接返回对应的已经预渲染好的 html,而不用再在客户端动态渲染或是服务端渲染 。

实际上是一种空间换时间的方法,会增大打包后的体积,提升预渲染路由页面的渲染时间。

参考

https://juejin.cn/post/6844903503362523143


服务端渲染 客户端渲染 预渲染
http://example.com/2022/09/10/服务端渲染 客户端渲染 预渲染/
Author
John Doe
Posted on
September 10, 2022
Licensed under