最近折腾了下React的ssr项目的搭建,之前折腾过一次没有太多的进展。这次重新开始搭建react的项目架构。项目源码:https://github.com/rt-zhangxuefei/react-ssr-template
特别感谢:慕课网的Delllee的课程。这里我使用了saga代替thunk,中间也遇到了一些坑,中间层代理使用了http-proxy-middleware。文章记录我搭建过程中遇到的一些问题:
ssr的过程
1)访问首屏时(任何url首次通过浏览器打开),请求到达node服务端
2)node服务根据访问的url匹配路由表(routte目录下的index.js)
3)匹配到的路由里面调用组件的loadData(自己定义的,用来获取数据),有需要获取数据的组件才添加一个loadData方法,这里匹配的路由可能是多个,所以会有多个loadData的方法,而且这些方法都是异步的(sagas)。
4)待所有异步操作完成,调用renderToString方法渲染出html字符串
5)express服务发送html字符串给浏览器(包含数据)和已经渲染好的dom字符串
6)浏览器获取到html字符串解析展示网页内容(ttfp)
7)浏览器根据script标签里面的src地址请求服务器,下载包含react客户端js文件
8)解析js,react执行,接管了整个页面的交互控制以及渲染
9)结束
项目结构如图
项目简介
自己模拟了几个接口(登录,判断登录,获取文章列表,评论列表),登录以后才能查看评论
支持less,css module
什么是注水和脱水
服务器端通过路由匹配出的组件的loadData方法(sagas)填充store,通过html字符串里面注入script标签引入变量的方式把store传给了浏览器,这个就是脱水。浏览器加载了包含reactjs的代码以后,把服务器注入过来的js对象的数据作为默认state传入createStore方法完成脱水过程。
服务器端渲染时react-router使用StaticRouter无状态路由
这里有个很重要的属性context,如下:
这个context参数会贯穿到浏览器和服务器端,成为一个数据交互的桥梁。比如判断前端路由重定向,404跳转等都是通过context作为判断来实现的。
css渲染
在具有样式的组件需要通过生命周期钩子注入css,让服务器端获取到并且渲染出来,这里就是一个应用(context作为数据桥梁)
组件的loadData(方法名称自己定义)
sagas就是store目录下的sagas
node作为中间层
所有的ajax请求都是通过node作为中间层来转发,这里使用了
http-proxy-middleware来实现,凡是url里面带有api的都进行转发。这样就会导致另外一个问题出来,那就是这个转发是针对浏览器的ajax请求。服务器端也会发同样的请求给后台api接口,差别只是url地址带没带host。axios对象的createInstance方法
服务器端使用的axios实例和浏览器端使用的axios实例不一样,作为参数传递给sagas,这里需要注意传参的方式:
服务器端使用:
客户端使用:
之所以能够这样做是因为watch sagas都是在浏览器端调用的(比如通过生命周期钩子,或者点击事件等),而loadData是服务器端调用获取数据用来填充store的。
造*?
虽然有了next.js,但有时自己造*有时是需要的。当然next.js是非常受欢迎的,值得用来开发实际的项目
结尾
再次感谢DellLee老师的课程。花了2周的时间,完成了一个react-ssr项目架构,项目里面还有2个未解决的问题,一个是css在服务器和客户端都渲染了一次,另外一个就是code splitting或按需加载的问题。希望在后续的学习过程中能够解决遗留的问题。如果你解决,请留言告诉我!
作者:张雪飞
出处:https://zhangxuefei.site/p/2166
版权说明:欢迎转载,但必须注明出处,并在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。