如何选择一款💓的React SSR框架

2,500 阅读8分钟

前言

找对象要看别人身高、体重、资产、性格、三观;技术选型也一样,前端的轮子玲琅满目,就像在你对面有无数个漂亮女孩一样,你怎么知道选择哪一个?

每个人都有每个人的小算盘:有的喜欢颜值高的,有的喜欢萌萌的,有的喜欢高高的;需求不一样,得出的结论也不一样;

技术选型也一样,业务不同那么选择也不尽相同;今天我们就来谈一谈如何选择一款让人心动的React SSR框架

我们先来看看Nodejs框架的发展历程吧

Nodejs框架发展历程

Node.js 是一个非常新兴的开发工具,它诞生自 2009 年,年龄远不如 Python、Ruby、PHP 等老大哥,但是它确实有史以来发展最快的开发工具,没有之一。

Express是第二年诞生的,它是最早的Nodejs框架,也是Nodejs框架的祖师爷

Koa充分地利用了js的新API,采用洋葱模型进行中间件处理,堪称一绝

Fastify基于插件架构扩展性非常好

我把Express、Koa、Fastify称作第一代Nodejs框架,因为后面的很多框架都是基于他们去进行扩展的

Nest可以基于Express、Fastify进行扩展

Egg基于Koa开发,他的理念是“约定大于配置”

Next、Nuxt、Remix、MidWay(hooks编写nodejs)、Meteor(有服务端渲染的example)、Sailjs(The MVC framework for Node.js)...

现在的Nodejs框架可谓百花齐放,可是应该怎么选择呢?首先我们可以排除掉第一代Nodejs框架,既然我们有了自行车为什么还要步行呢?用第一代Nodejs框架或者原生Nodejs也可以写出SSR应用,但是其中的样板代码太多,其实服务端渲染的流程是确定的,唯一变化的是前端页面,我们大可不必在重复的事情上下太多功夫。

专业的事情要交给专业的人来做,技术选型也一样;像Nest、Egg、MidWay、Meteor、Sailjs这些都偏重于后端服务,用它们来做服务端渲染简直是南辕北辙,所以大浪淘沙之后就只有Next、Remix了;接下来就是单挑环节;

Next vs Remix

Next是老牌服务端渲染框架,Star数量90.6k,并且社区完善,一直都在不断地更新,默认开启SWC,编译速度飞上天;

Remix是新秀,Star18.5k,他是来挑战Next的霸主地位的

初始化项目的难易程度

注意:这里指的初始化项目并不是说用cli clone出来一个项目,而是把项目相关的eslint规则、格式化配置、css、静态资源、打包配置、开发配置完全整理好所花费的时间

Next初始化

我的上一篇文章已经讲过Next项目的初始化,可以说Next的文档还是非常长健全的,有很多库集成的demo,下面我们来说一说它初始化过程中的优缺点:

  • ✅css解决方案健全:默认支持scss css module,文档对tailwind集成的方法也非常详尽,css in js的demo非常的多,可以快速上手

屏幕快照 2022-08-09 下午10.28.05.png图1:css in js demo

  • ❌eslint规则,官网有eslint规则配置,但是还不是最佳实践,需要自己增加一些其他的配置
  • ❌官方的webpack loader部分的配置无效,如图2是官方的配置

image.png图2:官方loader配置

官方的配置是有效的,但是某些特殊情况却不起作用;例如我们把静态资源文件放在/assets中,但是上线之后需要访问CDN,也就是说我们需要编译时将所有图片路径替换为CDN的图片地址,这个时候需要用到string-replace-loader,按照官方我们照葫芦画瓢这样一通配置:

webpack: (config, options) => {
    config.module.rules.push({
      test: /\.module.s(c|a)ss$/,
      use: [
        {
          loader: 'string-replace-loader',
          options: {
            search: '/assets/',
            replace: 'https://a.cdn.images/assets/',
          }
        },
      ],
    })

    return config
},

哪想到配置之后运行报错,如图3,但是如果我们不用Next直接在webpack这样配置是没有问题的:

image.png图3:string-replace-loader报错

度娘和谷歌都能够找到这个问题的答案,我们这里只是为了说明Next webpack配置的难度,Next有些地方确实很糟心,让我们再来看看Remix,希望Remix能够给我们带来光明

Remix初始化

Remix初始化过程中的优缺点:

  • ✅自动集成axios

  • ❌eslint规则,还是需要手动增加一些js基础配置

  • ❌css类型系统不健全,我们参照官方文档尝试在初始化的index.tsx中引入一个style,结果报错如图4,这个问题是由于没有配置样式文件的类型声明,这就增加了我们的配置成本:

    屏幕快照 2022-08-10 上午8.32.20.png图4:remix引入scss报错

    当我们尝试解决这个问题之后,再运行程序,又出现了如图5错误,此时我已经忍无可忍,一个小小的样式文件都有这么多错误,而且错误信息还如此模糊,我选择放弃调研Remix直接使用Next了,事实上我也是这么做的:

    屏幕快照 2022-08-10 下午9.16.23.png图5:样式文件报错

    但是我不甘心啊,一定到打破沙锅问到底,继续...

  • ❌不能自定义所有webpack配置

单独从项目初始化搭建的角度来看,Next比Remix要容易上手得多,接下来看一看打包部署流程的丝滑度

开发打包部署流程的丝滑度

Next

  • ❌没有使用webpack-dev-server,配置代理十分不方便: Next配置代理需要自己起一个Node服务,然后使用http-proxy-middleware进行请求的转发

  • ❌部署流程不顺畅:Next脚手架生成的项目模板是没有src目录的,但是打包的时候会报Ts错误

     Type error: Cannot find module './Button' or its corresponding type declarations.
    1 | import Button from './Button';
      |                    ^
    2 | 
    3 | export { Button };
    

    于是要耗费九牛二虎之力增加一个src目录,此时所有项目都报错了,只想说最终还是错付了,相信了Next,然后这还没有完,后面还会报错:

      warn - Attempted to load @next/swc-linux-x64-musl, but an error occurred: libc.musl-x86_64.so.1: cannot open shared object file: No such file or directory
    

    这只是一个版本问题,将Next版本限制在12.2.0就可以了,真的想放弃Next

Remix

Remix编译js文件还是用的babel,所以说打包的时候问题比Next要少一些

Next和Remix都需要借助pm2来进行管理,从开发打包部署流程的丝滑度来看的话Remix略胜一筹

性能

Next利用SSG & ISR来极致优化页面性能:对于不会经常更新的路由,可以直接打包为html文件,这样就可以永久缓存住,但是当接口数据更新了这么办?这就需要重新打包编译这就是ISR(增量静态再生),就是说每当接口数据改变我们就主动去编译一次但是要等到下一次请求页面才能看到结果;对于经常更新的页面则使用SSR;

Remix则充分利用stale-while-revalidate优化性能:stale-while-revalidate是一种Cache-Control策略,它是指缓存过期之后向服务端发起请求的同时,先返回过期的缓存,同时后台静默将过期的缓存更新为新数据,下一次请求页面则直接使用新数据

性能方面它们不相上下,都在做极致的性能优化创新

Remix有而Next没有的

  • Remix有一套完备的错误处理系统,就像是React的ErrorBoundary一样
  • Remix对于竞态问题做了很好的处理,比如一个商品页用户频繁加减商品,Remix只是前端界面先快速展示,中断一部分请求,把最终状态发送给服务端

SSR框架的调研报告至此结束,可能你们会问我你是怎么选择切入点去比较多个框架是否适合自己的?

技术选型切入点

建议1. 顺应自己的需求,就像选择对象的时候,你自己个子高你就希望对方也是个高个子;你希望性能好,那么你就着重关注性能这一块的内容

建议2. 如果是引入一个库,一定要看一看引入的难度,举个例子如果一个拖拽库里面依赖了某个css-in-js库,这个时候你就会觉得抓狂,因为写一个demo都很费劲;如果项目整体重构那么这个时候就要考虑很多方面:包体积、css解决方案多样性、打包配置的扩展性

建议3. 一定要选择尽量多的框架进行比较,只有多你才能不放过任何一个好用的框架,而不是仅仅搞两个框架在那里比较;像本文就是先从Nodejs所有的框架入手然后再逐一过滤

建议4. 不能只看文档或者别人的比较结果,一定要顺着文档去操作一遍,一定会有新的坑等着你;