打包node服务端_记一个Node渲染服务中的React SSR方案

目前我们前端使用两个Node服务 + 多个前端项目(react + webpack)。一个Node充当渲染服务;一个Node 对后端微服务做接口聚合充当node网关的作用;各业务块维护各自的前端项目。因前端项目跟node服务是分离的,所以需要一个适合自身架构的SSR方案。

=======================================================

前言

一直以来前端有几种场景是必须SSR(服务端渲染)来完成的,如SEO、分享页面到社交平台、弥补CSR(客户端渲染)首屏空白问题等。目前团队的前端项目由 node 来完成前端路由和静态资源的管理,偶尔有SSR的需要,是通过ejs把一些关键数据注入到HTML模板中来完成。因前后分离后前端项目已全面转至的 React,这样ejs就很难发挥作用,通常只用来注入一些关键的meta信息,无法胜任完整页面渲染的需求。现在流行的React SSR方案有Next.js、egg-react-ssr、umi等,这些方案都是node + react 全家桶式解决方案,支持约定式路由、开箱即用,但很难跟我们目前的架构相融合,那么就需要探索一个更适合我们现有架构的SSR方案。

(社交平台分享网页)

渲染流程概览

先来张图,这样就显得比较ok一些

b4af3511ff36a81d96b99209d79ee2eb.png
  1. 浏览器访问url,node-web路由匹配到对应ssr controller
  2. 读取front-web上 serverFun并调用,返回HTML文档。
  • 调用getComponent根据路由匹配出对应的页面组件PageComponent
  • 调用PageComponent 的getInitialProps获取后端数据填充到store或props
  • 提供一个serverFun暴露给node调用,serverFun内部通过renderToNodeStream完成页面渲染
  • 浏览器端进行hydrate渲染进行事件绑定。

这样设计的目的是为了降低node-web与front-web耦合程度,突出node-web作为静态资源容器的特点。

具体实现

Node Web 端实现

86e93020fb06ba89d3272d8b136d37dc.png

上面便是node-web中的核心代码:

  1. 读取 front-web/ssr/cfs-note-detail.js,调用ssr.script()把文件加入到File Watch,这样front-web更新时node-web就能够更新代码。
  2. 使用node vm虚拟机执行front-web 脚本,创建一个隔离的上下文ssrContext,可以mock 下window对象处理前端直接调用window对象引起的错误。
  3. 调front-web脚本暴露出来的getSSRStream方法得到HTML Stream 或 HTML String。
  4. 如果ssr执行失败使用ejs进行兜底渲染。

Front Web 端实现

webpack打包分为build:ssr和build:csr,使用webpack.DefinePlugin定义 __isBrowser__用来区分。ssr入口文件SSR Entry打包后的文件供node端调用,csr入口文件CSR Entry在浏览器端执行用于ReactDOM.hydrate。

SSR Entry

89ab8dfedf12e6cc4fbc909d0f11612b.png

上面便是front-web ssr脚本的核心代码:

  1. serverRender 方法:
  • 根据routes 和 ctx.path 获取当前的页面组件ActiveComponent
  • 如果ActiveComponent 存在getInitialProps方法则调用后,传入到store或props
  • Layout组件用于更改meta、注入hydrate需要的css和js资源

2. ssrConfig 配置:

    • type: 指定渲染方式'ssr'和'csr', 当指定csr时serverRender不会被调用,只将css/js注入到Layout,然后再浏览器端完成页面渲染
    • injectCss、injectScript: SSR完成后在浏览器进行hydrate渲染
    • serverJs、layoutJs: 调用renderToStream方法时,内部调用serverJs(ssr)或 layoutJs(csr)

3. getSSRStream: 暴露给node调用,返回HTML Stream 或 HTML String

Layout Component

65c9ac5cc536a1376734767c976123f0.png

Layout 组件的作用是服务端调用时返回 HTML template

SSR模式下Layout主要做了四件事:

  1. 注入hyrate所需的css/js
  2. 把页面组件getInitailProps()的返回值和store[mobx、redux等]组合成serverData放到全局变量window.__INITIAL_DATA__
  3. 设置全局变量window.__USE_SSR__ = ture
  4. 更改meta信息

CSR 模式下Layout只是把css/js注入到模板中

CSR Entry

a8792113e56cc21443edf430fb856416.png

CSR Entry 打包的结果在浏览器端执行,csr模式下执行ReactDOM.render,ssr模式下执行ReactDOM.hydrate。 同时调用了getWrappedComponent高阶组件,它的作用是:ssr模式下把window.__INITIAL_DATA__挂载到props,用于保证ReactDOM.hydrate的有效性;csr模式下调用页面组件的getInitialProps。

PageComponent

PageComponent中添加静态方法getInitialProps:

4e9871d9693d97eab6070123c36db15b.png

总结

方案优点:

  1. node-web 与 front-web解耦增加了node-web的扩展性,例如 node-web + front-web-2、node-web + front-web-3等可以使用相同方式接入,而不是每个站点各启一个node服务。
  2. 服务端和客户端共用代码,ssr与csr通过config进行随时切换

缺点:

  1. front-web需要把依赖全部打包到ssr/[page].js,无法externals node_modules、split chunks,打包文件较大
  2. node-web执行脚本过于黑盒,里面的逻辑略显复杂。

================2020.5.21 更新:服务端渲染失败兜底=====================
例如: /product/123445 重定向到 /product/123445?csr=1 进行客户端渲染

091f2f2472b5cd2dcc7d02b1683cdfa6.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Node.js是一个基于Chrome V8引擎的JavaScript运行环境,它使JavaScript可以用于服务开发。React是一个用于构建用户界面的JavaScript库,它提供了组件化的开发方式和高性能的渲染能力。SSR(Server-Side Rendering)是指在服务React组件渲染成HTML字符串后再返回给浏览器,以提高页面的渲染性能和SEO友好度。可以通过使用React.js和Node.js来实现SSR。 在使用React.js和Node.js实现SSR时,可以采用以下步骤: 1. 在Node.js搭建一个服务器,并配置好路由,用于处理HTTP请求。 2. 在服务使用React.js渲染组件,并将渲染后的HTML字符串返回给浏览器。 3. 在浏览器使用React.js重新渲染组件,并与服务渲染的HTML字符串进行比对,以确保两者一致。 4. 在浏览器绑定事件和处理用户交互,以提供更丰富的用户体验。 使用Node.js和React.js实现SSR可以带来以下好处: 1. 提高页面的初始加载速度,因为服务渲染的HTML字符串可以更快地呈现给用户。 2. 改善SEO(Search Engine Optimization),因为搜索引擎可以直接抓取服务渲染的HTML内容。 3. 提高用户体验,因为在页面加载过程,用户可以看到内容的逐渐呈现,而不是空白的加载界面。 需要注意的是,使用Node.js和React.js实现SSR需要一定的技术储备和对这两个技术的深入了解。同时,还需要考虑服务器的性能和可扩展性,以确保能够处理大量的并发请求。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [详解基于React.js和Node.js的SSR实现方案](https://download.csdn.net/download/weixin_38665162/12945005)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [JavaScript Applications with Node.js, React, React Native and MongoDB](https://download.csdn.net/download/weixin_43960172/10904948)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [Java在小程序开发方面的优势及应用](https://download.csdn.net/download/milk416666/88250412)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值