SSR,Next.js,Next.js 12和React 18

在Orka入职,我被分配的第一个任务就是探索公司现有前端框架升级成Next.js 12优点和代价。这个问题,交给实习生来做,其实是有一点点“大”的。没办法,硬着头皮接下来了这个活儿。结果这一研究,算是“牵一发而动全身”,一下子引出了很多相关概念。这篇文章用来记录一下我对当前前端SSR领域的一些见闻。

为什么要用SSR

这个故事如果从很久很久以前讲起的话,那得追溯到后端模板时代——没错,就是那个现在还在用的Flask模板一类的东西(如果你熟悉Python的Flask框架的话,不过SpringBoot也有类似的东西)。之后,人们发现用后端模板引擎渲染的复杂度逐渐提高,于是“渲染”这个工作就交给了前端,在React中,就对应着我们的ReactDOM.render()方法(在React 18中改为了ReactDOM.createRoot().render())。再后来,人们又发现,如果全部交给前端渲染,似乎前端的压力会比较大,于是就出现了一个很大的问题——首页白屏

首页白屏会影响到用户体验,但是更重要的是,它直接影响到了SEO。因此,对于to B的网站,尽管使用前端渲染,没有问题的。但是对于to C的网站,为了留住用户,为了SEO,SSR(server-side rendering,服务端渲染)就变成了一个很重要的东西。

Next.js做了什么

其实,Next.js并不是100%的SSR,更精确地讲,它做的是一个叫做“同构渲染”的事情。即,使用同一份代码,由Next.js先在服务端获取到需要的数据,渲染成HTML代码,再由前端将HTML代码和JavaScript hydrate起来。(对应到react-dom/serverReactDOMServer对象的方法和ReactDOM.hydrate()方法。那么,Next.js具体做了什么呢?除了Next.js官网的信息,让我选三点的话,我认为它带来了以下好处:

  1. SSG和SSR。Static Site Generation (SSG)在build time生成静态页面,SSR发生在request time。前者加速了SSR,后者提供SSR框架。
  2. File-system Routing。自带Route,只需要在./pages文件夹下面建立对应的js文件,即可建立一个新的页面。
  3. Built-in CSS support。Next.js会自动混淆CSS类名,支持component level, global level和js file level的CSS,保证CSS类名不互相冲突,并内置支持SASS。

其它的话,middleware的部分我目前做的比较少,只知道Next.js也提供了很多便捷的接口。

Next.js 12做了什么

Next.js 12引入了一系列的新功能,让我概括三点最重要的亮点的话,我认为是,Rust compiler, Middleware和React 18。关于Middleware,有空我再详细研究,React 18将会在本文下一部分详细描述,关于Rust compiler,我的感受是,还不错。

根据官网的描述,Next.js 12采用的新compiler可以达到3倍的refresh和5倍的build,比babel快了17倍。我实测下来,build我们自己的项目,end-to-end的事件从782s变成了695s,提升了11.1%——可能的原因是我们使用的image optimizer花了很多时间,而这不是Next.js的控制范围。Anyway,使用Next.js在hot update的时候还是会很香的。

Next.js 12将会和React 18产生什么奇妙的化学反应

React 18推出了三个大改进:Automatic batching、Suspense on the server和New APIs for app and library developers(见我的另一篇文章)。其中,Suspense就是用来给SSR使用的。

简单来说,React 18以前的SSR只允许当服务端渲染好了整个HTML页面以后,再将内容一股脑地返回给客户端,但是有了Suspense,服务端的内容可以分批次地传给客户端。目前Next.js 12和React 18已经趋于稳定,我们后续的组件可以考虑使用Suspense来提升用户体验。