TAT.Johnny React 服务器端渲染实践小结
In 未分类 on 2015年10月31日 by view: 25,180
34

背景

为什么是 React?

React 今年在国内特别火,一时间虚拟 DOM(Virtual DOM)等酷炫概念一下刷新了很多前端开发同学的三观,关于性能优劣的争论也在知乎上看到不少。不得不说 React 解决了一些前端项目开发的痛点,而我最近的一年多的工作重心,都在兴趣部落这样一个基于兴趣社交的 web 产品上,有很多感同身受的地方。兴趣部落这个产品从初期只有移动端的 2、3 个页面,发展到现在 50+移动页面,加上 PC 版的最近上线,中间经历了从 2-3 人的小项目到 10+人团队的大型前端项目的巨大转变。这个过程中除了人员相对业务的线性增加,代码量、维护成本也是以指数速度增长的,很快代码臃肿、难以维护与测试等问题就凸显出来。虽然内部经过一些轻量的重构优化,但开发模式还是与高度的迭代节奏很不匹配。这时候,React+Webpack 的组件开发模式让我眼前一亮,暗下决心要让这样的先进开发模式推广到项目团队,好东西一定要让大家有所受益,而不仅仅是技术的尝鲜、摆设。

为什么要在服务端渲染?

除了代码维护性的问题,项目代码膨胀导致的一个问题是基础库、公共资源的变大,从而导致页面加载性能日益下降。在使用 React 时,也第一时间考虑到对加载性能的影响,本来页面就要等待 ajax 返回数据,页面会不会因为 React 的引入变得更慢呢?不要说 React 那点大小根本不是事儿,在移动网络下(包含 2G 啊 T_T)任何资源都是很珍贵的。有没有同时提高代码维护性,又能提升页面加载速度的好事呢?答案终于回到主题,就是在服务端渲染 React。这里可以一并总结该方案的好处:

  1. 利于 SEO
  2. 加速首屏渲染速度
  3. 享受 React 组件式开发的优势:高复用、低耦合
  4. 前后端维护一套代码(代码同构)

原理

如果听到 AngularJS 在服务器端使用,你可能会很惊讶。但是对 ReactJS,完全不必如此,因为 React 很好的分离了 DOM 的操作,使得在服务器端输出页面字符串有了可能。最新的 React 版本 0.14.1 中,已经彻底将服务端需要的源码分离出来。react-dom/server

我们使用的核心 API 就是 ReactDOMServer.renderToString,它只会在服务端使用,并返回组件渲染数据后的 HTML 字符串。而接下来要做的,就是将这个 HTML 片段拼接回页面模版,返回到前端浏览器进行用户侧的显示。

这里还要补充一句,React 组件在服务端的生命周期方法,只会执行到 componentDidMount 之前的方法,因为在服务端没有组件挂到文档 DOM 树的概念。

核心步骤

Node 端的组件加载

我们要在 Node 端渲染组件,首先需要加载到组件,像这样:

但是 Node 默认状况是不懂怎么解析 JSX 文件的,所以要在之前加上:

React 组件渲染

加载到了 React 组件,等到后端的数据 data 也拿到后,就可以进行组件的渲染了:

data 是一个 json 对象,比如 data={'type':'test'},这时候 data 会以 props 的形式传递给组件,类似于在 jsx 中这样写:

拼接返回 HTML

这时候组件的 HTML 已经渲染完毕了,可以作为 HTTP 的返回体的一部分返回到浏览器了,这时候大家可以根据自己的项目框架进行操作。我们在这里使用了 Koa 的框架,并使用了 ejs 的模版,所以可以参考代码:

到这里基本就完成了在服务端进行 React 组件的渲染,但其中还有一些小问题,我们接着继续探讨。

延伸话题

关于前后端共用代码的问题

我们的 JSX 文件在前端与 Node 端是完全复用的,而服务端用到的实际代码比浏览器需要的更少,但还是有一些差异需要注意:

前后端环境的判断方法

我个人建议通过 window 对象来判断,因为之前使用过 moduel 对象来判断,会因为 webpack 的打包代码导致客户端侧的运行会有问题。