作者 | 褚杏娟 Tina 核子可乐
关于“该用 Preact 还是 React”的争论由来已久。Preact 是 MIT 许可下的开源软件,在 GitHub 上有超过 26k 的 star,在 NPM 上每周有 1/4 百万的下载量。而源于 Facebook 的内部项目 React 在 2013 年开源后已经成为主流前端框架之一。
百度很久之前就要求内部全面停止使用 React / React Native,阿里内部也已经有部分业务开始试点 Preact。美国电商企业 Etsy 近日也用脚投票做出了选择。
高级软件工程师 Ben Sangster 宣布 Etsy 已从 React v15.6 迁移到了 Preact 10 。Preact 比 React 小得多,性能也比 React 快,Sangster 认为采用 Preact 能降低迁移大型代码库产生的风险。据悉,Etsy 大约在 2015 年左右开始使用 React。
我们用 Preact 替换掉了全部的 React v15.6 。这是一个巨大的胜利。与迁移到 v16 相比,迁移到 Preact 要容易得多(对旧代码的重写或重构要少得多)。
Sangster 表示迁移是无缝的,React v15.6 和 Preact 可以使用完全相同的 client,对于 Etsy 的开发人员来说,真正重要的改进是他们可以开始编写更现代的 React。
Preact 还是 React ?
Etsy 目前拥有两大主要产品栈。在面向买家的页面中,Etsy 使用的是基于 PHP 服务器的渲染方案,再配合客户端上的 jQuery/ 原始 JS。在面向卖家的页面时,Etsy 选择使用由 React 渲染的 SPA 再配合一点点基于服务器的 HTML 渲染,借此尽可能减少从同一 PHP 服务器端堆栈接收的数据总量。
在相关博客文章中,Sangster 详细解释了 Etsy 迁移到 Preact 而不是最新版 React 的三个原因。
首先,采用 Preact 能最大程度地降低迁移风险。开发人员一般都比较喜欢 React 16 的新特性(例如,error boundaries、fragments、错误堆栈跟踪、自定义 DOM 属性、React 16.8 中的 hooks),虽然 React 16.0 文档提到了一些小的重大更改,但也有不少开发人员报告了迁移的痛苦。Discord 的 Michael Greer 说:“并不是所有的 package error 都那么容易被发现,这才是真正的痛苦所在。我们遇到了一个错误,花了 2 天时间才找到对应的 library,你可能也会遇到同样的问题。”
对于 Etsy 来说,虽然升级到 React v16 在保障长期兼容性方面堪称最为稳妥的选项,但要求 Etsy 付出高昂的代价。在新版本中很多生命周期方法已经被弃用和重新命名,所以 Etsy 得在代码运行模块中调整这些被弃用的方法名称。虽然 Etsy 打算选择 Preact,但这些 codemods 还是要用的,只是 Preact 允许其先迁移、之后再慢慢修改。React 升级则要求把 codemods 也作为升级流程的一部分,这样登台工作和撤销操作就会变得更加困难。
另外,Etsy 的卖家工具中大量用到现在已被弃用的 theseus/Component helper,所以其在 React v16 中就面临着缺少生命周期方法可用的问题。另一方面,Web Toolkit 也用到不少已经弃用的生命周期方法,所以需要配合重构和回归测试才能安全完成迁移。
因为 FES 团队的实验架构已经明确基于 Preact,而且有意共享 Web 工具包,所以选择迁移到 React 会大大提高在 Preact 与 React 之间共享代码成果的难度。虽然这个问题最初只影响到 Web Toolkit,但后续也必然会干扰到 Etsy 检测未来卖家工具子应用架构新版本的能力(其中用到了 Preact SSR 服务)。
但迁移到 Preact 的话,虽然与 React 一样,Etsy 也需要完成从 React.createClass 到 create-react-class 包,以及从 React.PropTypes 到 prop-types 包的升级。但是, Preact 的 API 与 React 兼容,这意味着团队不用进行任何更改。由于 Preact 强调与 React v15 和 React v16 的兼容性,迁移到 Preact v10.4.2 将变得更加容易。从开发人员工具的角度来看,采用 Preact 似乎没有任何重大障碍。
Sangster 也从与现有库、现有工具、未来规划等兼容性问题上对两者进行了详细对比:
与现有库的兼容性问题上的对比:
与现有工具的兼容性问题上的对比:
与未来规划的兼容性问题上的对比:
其次,Etsy 的前端系统团队已经在使用 Preact。在 Etsy 中统一使用 Preact 可能会使开发人员的生活更轻松。
Sangster 介绍,FES 团队(Etsy 的前端系统团队)的新项目架构已经基于 Preact,这并没有带来兼容性方面的问题。同时,还统一了 Etsy 内部使用的 Preact/React 库,随时间推移大大降低了开发者的工作难度。同时在 React 和 Preact 中支持 / 测试 Web Toolkit 等工具必定会增加 FES 团队及其他同事的工作负担,导致团队很难实现全面的工具与架构共享。在 Preact 成为整个 Etsy 中的唯一标准后,这类问题也就随之消失了。
最后,Preact 的包大小(Preact v10.4.5 为 4KB)比 React 的小六倍(React v16.13.1 添加 react 和 react-dom 之后为 38.5KB)。JavaScript 体量越大,延迟 (time to interactive) 也就越大,消耗的内存和 CPU 也会越大。
Sangster 进行了简单的对比,需要注意的是,下面列出的数字并不包括三种库都具有的包的大小——例如 prop-types or create-react-class。各包大小均取 Bundlephobia 上的最小值,且皆为 gzip 格式。
可以看出,从 v15.6.2 升级至 v16.13.1 能在 gzip 格式下节约 5.2 KB 空间,而从 v15.6.2 升级至 Preact v10.4.5 则能在 gzip 格式下节约 37 KB 空间,因此,使用 Preact v10.4.5 替代 React v16.13.1 能在 gzip 格式下节约 32.5 KB 空间。
Sangster 强调说:“我们有很多古老的‘无主’代码和很多旧的库,升级到 React 16 会导致一些 API 问题(尤其是 Portals/legacy Context/refs),需要做大量的工作才能够解决。相反,我们迁移到 Preact,可以将代码重构为可用的、最现代的东西,而不需要去做同步升级组件 / 库这些事情。”
迁移计划
在假设所有库的兼容性都跟前文中预测的一致,而且 Preact 的兼容性也不出意外问题的情况下,Etsy 的整个迁移流程将如下所示:
- 先切换、再升级至 Preact v10.4.5,这样我们就能在 Preact 与 React 两种渲染驱动方案之间往来切换以验证迁移效果。
- 使用 codemods 以迁移至“现代”React 生命周期方法(不算是硬性要求,因为 Preact 也完全能够支持同一 API 的两个版本,但我们觉得这是个很好的长期发展目标)。
- 彻底移除 react-router-redux (可以在 Preact 迁移的同时并行完成)。
- 将 react-redux 升级至 7.2.0 版本(可能还涉及升级 redux)。
- 将 react-router 升级至 5.2.0 版本(也可能要升级到 6.x 版本,具体取决于 5.2.0 版本够不够稳定)。
目前,Etsy 的迁移工作卡在了移除 React.PropType 和 React.createClass 这一步,因为 Web 平台团队对 ESM 语法进行了升级。
整个迁移过程中的挑战在于,大部分工作都很复杂,即使是单行 /upgrade 也可能需要大量时间。其次,react-router 上的重大变更也要求 Etsy 对卖方工具中的子应用架构做出侵入性的调整,用以重新设计加载 / 路由的方式。另外,移除 react-router-redux 的工作量也不小,不过好在这几项任务还算相对独立、互不影响。
查看更多:
https://github.com/mq2thez/blog/blob/main/upgrade-react-etsy/preact-vs-react.md