时间:2021-05-26
一、前言
为什么需要服务端渲染?什么情况下进行服务端渲染?笔者认为,当我们要求渲染时间尽量快、页面响应速度快时(优点),才会采用服务器渲染,并且应该“按需”对页面进行渲染 ——“首次加载/首屏”。即服务端渲染的优势在于:由中间层( node端 )为客户端请求初始数据、并由node渲染页面。那客户端渲染和服务端渲染有什么差别?服务端渲染究竟快在哪里呢?
二、原因与思路
客户端渲染路线:1. 请求一个html -> 2. 服务端返回一个html -> 3. 浏览器下载html里面的js/css文件 -> 4. 等待js文件下载完成 -> 5. 等待js加载并初始化完成 -> 6. js代码终于可以运行,由js代码向后端请求数据( ajax/fetch ) -> 7. 等待后端数据返回 -> 8. react-dom( 客户端 )从无到完整地,把数据渲染为响应页面
服务端渲染路线:2. 请求一个html -> 2. 服务端请求数据( 内网请求快 ) -> 3. 服务器初始渲染(服务端性能好,较快) -> 4. 服务端返回已经有正确内容的页面 -> 5. 客户端请求js/css文件 -> 6. 等待js文件下载完成 -> 7. 等待js加载并初始化完成 -> 8. react-dom( 客户端 )把剩下一部分渲染完成( 内容小,渲染快 )
说明:对同一个组件,服务端渲染“可视的”一部分( render/componentWillMount部分代码 ),为确保组件有完善的生命周期及事件处理,客户端需要再次渲染。即:服务端渲染,实际上也是需要客户端进行 再次地、但开销很小的二次渲染。
时间耗时比较:
1. 数据请求:由服务端请求数据而不是客户端请求数据,这是“快”的一个主要原因。服务端在内网进行请求,数据响应速度快。客户端在不同网络环境进行数据请求,且外网http请求开销大,导致时间差(主要原因)。
2. 步骤:服务端是先请求数据然后渲染“可视”部分,而客户端是等待js代码下载、加载完成再请求数据、渲染。即:服务端渲染不用等待js代码下载完成再请求数据,并会返回一个已经有内容的页面。
3. 渲染性能:服务端性能比客户端高,渲染速度快( 猜测,该项数据不详 )。
4. 渲染内容:服务端渲染会把”可视“部分先渲染,然后交给客户端再作部分渲染。而客户端渲染,则是从无到有,需要经历完整的渲染步骤。
三、注意事项与问题
0. 项目依赖什么?答:node端:express、react-dom/server、webpack。前端:React、mobx(一个更好的redux)、React-router、webpack
1. 前端/node端共用那部分代码?答:node端/前端有各自的入口文件,server.js/client.js,通过react-router的路由配置文件routes.js作中间层
// routes.jsmodule.exports = ( <Route path="/" component={ IComponent } > <Route path="/todo" component={ AComponent }> </Route> </Route>)2. 代码是由前后端共享,那如何分平台地操作不同代码?答:通过webpack。对共享代码,进行不同平台的,webpack(babel)编译,通过在webpack.config.js中加入
// webpack.client.config.jsplugins: [ new webpack.DefinePlugin({ '__isServer__': false, '__isClient__': true }) ]// webpack.server.config.jsplugins: [ new webpack.DefinePlugin({ '__isServer__': true, '__isClient__': false }) ]// xxx.jsif( __isServer__ ) { ...}else { ... }4. 组件的生命周期是如何的呢?答:componentWillMount( node端 ) -> render( node端 ) -> 客户端生命周期和以前一样
5. 拉取数据后如何处理呢?答:先在node端根据数据渲染好,再把数据随页面返回至前端,再由React根据数据进行渲染校对( 若前后端渲染结果不一致将报错 )。应该在componentWillMount让组件进行本地的数据同步
// 组件.jscomponentWillMount() { if( __isClient__ ) { this.todoStore.todos = window.initTodos; }} // node端返回`<!doctype html><html lang="utf-8"> <head> <script> window.initTodo = ${...}</script> </head> <body> ... </body> <script src="/static/vendor.js"></script> <script src="/static/client.bundle.js"></script>6. 前端/node端“入口文件”通过webpack构建有什么不同?答:前端是为了解析JSX与es6代码(包括mobx的es6 decorator),node端除了以上,还需要加入babel-plugin-transform-runtime,是为了在node良好地运行es7 async / awatit
7. 如何保证node端能够先请求数据然后再渲染?答:es7的async / await语法
8. 前端的react-router路由与node端路由如何配合?node如何知道该路由是渲染哪个数据呢?答:前端是以前的react-router配置,node端是react-router的match/RouterContext// 共享文件routes.js
const routes = ( <Route path="/" component={ IComponent } > <Route path="/todo" component={ AComponent }> </Route> </Route>)// 前端入口文件client.jsrender( <Router routes={ routes } history={ browserHistory } />, ele)// node端入口文件server.jslet app = express();app.get('/todo', (req, res) => { match({ routes: routes, location: req.url }, async (err, redirect, props) => { // match会帮我们找到要渲染的组件链,注:上面一行使用了async语法,因此可以在render之前使用await运行拉取数据的代码 let html = renderToString(<RouterContext {...props} />) res.send( indexPage(html) ) }}) // node端返回 let indexPage = (html)=>{ return ` <!doctype html> <html lang="utf-8"> <head> <script> </script> </head> <body> <section id="hzpapp" >${html}</section> </body> <script src="/static/vendor.js"></script> <script src="/static/client.bundle.js"></script> </html>}9. client.js中是否还能继续使用webpack的require.ensure ? 答:可以。但闪白明显,且node端返回html后会有报错,在加载脚本后该错误能忽略。
10. 若我使用的是mobx,该如何实例化store ? 答:每一个node请求,都应该返回一个新的独立的store实例,而不是每个node请求共用一个store实例(笔者易犯)。
本demo地址( 前端库React+mobx+ReactRouter ):https://github.com/Penggggg/react-ssr
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
学习react也有一段时间了,使用react后首页渲染的速度与seo一直不理想。打算研究一下react神奇服务端渲染。react服务端渲染只能使用nodejs做
因为对网页SEO的需要,要把之前的React项目改造为服务端渲染,经过一番调查和研究,查阅了大量互联网资料。成功踩坑。选型思路:实现服务端渲染,想用React最
首先,这个例子用到了服务端渲染的技术。服务端渲染,说白了就是在服务端使用模板引擎,这里我先简单的介绍一下服务端渲染与客户端渲染之间的区别。服务端渲染与客户端渲染
前后端同构渲染:当客户端请求一个包含React组件页面的时候,服务端首先响应输出这个页面,客户端和服务端有了第一次交互。然后,如果加载组件的过程需要向服务端发出
我们已经熟悉React服务端渲染(SSR)的基本步骤,现在让我们更进一步利用ReactRouterV4实现客户端和服务端的同构。毕竟大多数的应用都需要用到web