2016年11月份左右,我们开始尝试用react作服务端渲染。大约2016年12月底react同构项目搭建完成,并应用到一个后台项目中。期间踩过很多坑,总结如下。

什么是服务端渲染

"服务端渲染"一词在前端框架盛行之前并未被提及,但它确实存在。比如.php文件就直接支持用语法来渲染html,还包括java的jsp技术等。那为何在前端框架盛行之后,这个词屡次被前端所提及。是因为前端框架(拿最具代表性angularjs举例)有一个弊病,先一代前端框架的实现并没有脱离于浏览器去作架构,以至于这些框架模版的渲染需要在浏览器环境中完成。

那么问题就出现了,模版和数据必须通过浏览器分别请求获取,然后在浏览器中编译渲染。相对于服务端直接吐出编译好的模版在速度上是有差异的,要知道评价网站性能的一个重要指标是白屏时间。前端渲染需要:1.初始化前端框架引擎;2.拉取模版;3.拉取数据;尤其在手机端低网速低性能情况下,白屏时间会被放大。虽然我们先前说过,服务端渲染早就不是什么新技术,各家脚本语言都完美支持,但是作为优秀的前端框架让开发效率得到了非常大提升。而恰好上一代前端框架模版渲染依赖于浏览器,并不能在后端编译模版,前端框架和后端模版技术我们只能选其一。这让前端真的无法割舍优秀的前端框架,于是就有了后一代更加强悍的前端框架。虚拟dom可以不依赖于浏览器模版渲染(react是这种技术的实现者),支持后端渲染,能完美解决白屏问题。而就在框架迭代过程中,“服务端渲染”重新被前端者推向了技术热词。

什么是同构

一个模块既想要在前端环境(浏览器下)运行,又想在后端环境中复用,比如前端轮询更新某个模块(js编译模版)与首次渲染(后端语言编译模版)是同一个模块是非常难的。第一个难点是语言,前端语言是javascript,后端是php ,java等。nodejs的出现解决了语言问题,让开发者看到了前后端能复用一个模块的希望。但是依然有别的问题,比如浏览器的js解释器版本更新困难,一些特性不支持(比如模块管理,es6,7新语法等),前端只好寻求一些构建工具或其它预编译技术处理,比如webpack,babeljs等。而服务端呢?一个模块为了在前端环境运行经过了各种预编译,服务端运行时也必须作一些处理。比如去掉图片,css等资源模块(webpack 会把资源当作模块),去掉事件绑定功能(因为这是针对浏览器的)等。所以,对于构建脚本来讲,既要考虑针对后端环境构建,也要考虑针对前端环境构建。为了让同一模块既能在后端运行,也能在前端运行必须两端都要构建,简称同构。

同构的坑

目前来看,只有react支持服务端渲染较好,webpack 从2016年12左右开始逐步支持服务端构建。服务端渲染的问题逐渐演化成同构问题,最后是一个构建工作。前端环境与后端环境差异巨大:

1.平台升级不统一

浏览器js引擎升级困难。为了实现能用高级的语法,前端需要预编译用babeljs。而nodejs呢?完全不需要,新的nodejs版本对高级语法兼容相当好了。从版本升级来看,迭代速度相对快。而反观浏览器,升级慢,内核不统一兼容性更是老火。

2.前端特性,后端不需要

前端组件化是一个相当吸引人的思维。webpack能把资源当成模块,大大迎合了组件化思维。而react恰恰又把组建这 一概念实现得相当优雅,加上webpack它们就是天生一堆,组件化得到了进一步升华。现在很多react模块都希望用webpack来构建。然后后端呢,需要webpack来构建吗?webpack构建再强大,无非解决资源模块问题,平台兼容问题。后端实现模版渲染,并不需要资源(css等),平台本来就已经够新了,更不需要解决平台带来的兼容问题。前端所需要的,恰好是后端不需要的。同构完全在解决一个用webpack思维写的模块,怎么去掉其资源模块,怎么能不用babeljs,甚至是后端不构建行不行?最后解决情况是:1,webpack我是一定要用的在react中;2,后端可以根据情况选择构建工具,也可以选择webpack构建后端。3,最后根据大量评估,我选择了用webpack构建前后端,这就是我的同构。

3.同构的过程是学习webpack的过程

解决服端渲染,同构问题最后演变成了学习webpack构建工具的过程。webpack既要构建前端,又要构建后端。所以css-loader具体是干啥,style-loader, file-loader等具体干啥必须清楚。要想构建实现工程化,commonjs vs commonjs2, amd等概念必须弄明白,还有webpack的api的每一个属性节点是起什么作用,必须熟悉。webpack的构建性能也是一大问题。构建打包后引发的源码调试等问题都必须解决。

服务端渲染,同构不是解决问题唯一途径

在手机端,我们减少白屏时间的方法很多,比如将资源模版等预埋在客户端里。pc端网络环境并没有这么极端,白屏问题影响不严重。当然追求极致速度和开发体验时,同构也许在所难免。

参考项目

https://reactjsnews.com/isomorphic-react-in-real-life

https://github.com/DavidWells/isomorphic-react-example

https://github.com/8427003/bdj-build