什么是SSR(Server side Rendering)
直接起一个express服务
启动后,可以看到页面显示了hello world。这就是服务端渲染,就是服务器返回了一堆html字符串,然后让浏览器显示。那说到SSR就要讲到跟其相对应的CSR(Client side Rendering)
什么是CSR(Client side Rendering)
使用react脚手架生成一个项目跑起来,这个就是客户端渲染
body中除了兼容处理的noscript标签之外,只有一个id为root的标签。那首页的内容是从哪来的呢?很明显,是上面的script中bundle.js拉取的JS代码控制的。
CSR和SSR的区别
因此,CSR和SSR最大的区别在于前者的页面渲染是JS负责进行的,而后者是服务器端直接返回HTML让浏览器直接渲染。
为什么要使用SSR
为了弥补CSR缺点
- 首次渲染,白屏时间过长: 由于所有 JS 都打包在一个文件中,在这个 JS 加载完成之前,在页面上是看不到任何东西,这就会让用户感受到‘白屏’
- SEO 不友好:对于搜索引擎来说,只能在页面中发现一个 DOM 节点,不利于 SEO;因为一些普通的搜索引擎爬虫只认识html结构的内容,而不能识别JS代码内容。
SSR 最早是为了解决单页应用(SPA)产生的 SEO、首屏渲染时间等问题而诞生的,在服务端直接实时同构渲染用户看到的页面,能最大程度上提高用户的体验,简化流程是:
- 服务器端使用 renderToString 直接渲染出的页面信息为静态 html。
- 客户端根据渲染出的静态 html 进行 hydrate(水合),做一些绑定事件等操作。
大白话就是:一套代码在服务器跑一遍然后再在客户端上跑一遍;服务端渲染完成页面结构,浏览器渲染完成事件绑定;专业来讲就是同构。
SSR实现的本质:虚拟DOM的存在
前面说了SSR 的工程中,代码会在客户端和服务器端各执行一次。虽然都是JS代码,既可以在浏览器上运行,又可以在 Node 环境下运行。但事实并非如此,如果你的 Reac代码里,存在直接操作 DOM 的代码,那么就无法实现 SSR 这种技术了,因为在 Node 环境下,是没有 DOM 这个概念存在的,所以这些代码在 Node 环境下是会报错的。
但是有了虚拟DOM的存在,React或者Vue这种项目使得SSR成为了可能。在服务器,我可以操作 JavaScript 对象,判断环境是服务器环境,我们把虚拟 DOM 映射成字符串输出;在客户端,我也可以操作 JavaScript 对象,判断环境是客户端环境,我就直接将虚拟 DOM 映射成真实 DOM,完成页面挂载。
以下为SSR的流程,重点在第3步和第10步,当客户端接收到 JavaScript 文件后,要根据当前的路径,在浏览器上再判断当前要展示的组件,重新进行一次客户端渲染,这个时候,还要经历一次客户端路由(前端路由)。
SSR在React的实现
若要使用 react 来实现服务端渲染,一般需要 3 个目录。
- server: 包含 node 的后端工程
- client: 包含 react 的前端工程
- shared: 包含前后端公用的组件代码。
在同构中,只有组件的代码是可以公用的,而路由这样的代码是没有办法公用的,在 SSR 中,服务器端的路由和客户端的路由不一样,也就意味着服务器端的入口代码和客户端的入口代码是不同的,React 代码是要通过 Webpack 打包之后才能运行的,也就是第 3 步和第10 步运行的代码,实际上是源代码打包过后生成的代码。上面也说到,服务器端和客户端渲染中的代码,只有一部分一致,其余是有区别的。所以,针对代码运行环境的不同,要进行有区别的 Webpack 打包。
"scripts": {
"dev": "npm-run-all --parallel dev:**",
"dev:build:server": "webpack --config webpack.server.js --watch",
"dev:build:client": "webpack --config webpack.client.js --watch",
"dev:start": "nodemon --watch build --exec node \"./build/bundle.js\""
},
SSR主流程
SSR实现要点
node只是SSR的一个中间层,用于做React代码的服务器端渲染,node需要的数据通常由API服务器单独提供。一是为了工程解耦,二是为了规避node服务器的一些计算性能问题。另外,在请求数据的时候,客户端可能存咋跨域问题,所以也可以通过node代理转发拿到API服务器的数据。
总结:
使用 SSR 在解决问题的同时,也会带来非常多的副作用,比如使得原本简单的React项目变得非常负责,项目的可维护性会降低,由于代码会同时在服务器和客户端跑,代码的问题追溯也会变的比较困难。除非项目特别依赖搜索引擎流量,或者对首屏时间有特殊的要求,否则不建议使用 SSR
参考目录