2022-09-23前沿技术00
请注意,本文编写于 578 天前,最后修改于 578 天前,其中某些信息可能已经过时。

本周精读的文章是 Comparing the New Generation of Build Tools

前端工程领域近期出了不少新工具,这些新工具都运用了一些新技术或者跨领域技术,实现了一些突破,因此有必要了解一下这些工具都有什么特性,以及是否可以投入生产环境。

由于原文比较啰嗦,所以具体用法和支持细节不在这里展开,如果想进一步了解细节,可以直接阅读 原文

精读

按照从底层到上层的封装粒度,以 esbuild、snowpack、vite、wmr 的顺序介绍。

esbuild

esbuild 使用 go 语言编写,由于相对 node 更为底层,且不提供 AST 操作能力,所以代码执行效率更高,根据其官方 benchmark 介绍提速有 10~100 倍:

esbuild 有两大功能,分别是 bundler 与 minifier,其中 bundler 用于代码编译,类似 babel-loader、ts-loader;minifier 用于代码压缩,类似 terser。

使用 esbuild 编译代码方法如下:

esbuild.build({
  entryPoints: ["src/app.jsx"],
  outdir: "dist",
  define: { "process.env.NODE_ENV": '"production"' },
  watch: true,
});

但由于 esbuild 无法操作 AST,所以一些需要操作 AST 的 babel 插件无法与之兼容,导致生产环境很少直接使用 esbuild 的 bundler 模块。

幸运的是 minifier 模块可以直接替换 terser 使用,可以用于生产环境:

esbuild.transform(code, {
  minify: true,
});

由于 esbuild 牺牲了一些包大小换取了更高的执行效率,因此压缩后包体积会稍微大一些,不过也就是 177KB 与 165KB 的区别,几乎可以忽略。

esbuild 比较底层,所以可以与后续介绍的上层构建工具结合使用,当然根据工具设计理念,是否内置,内置到什么程度,以及是否允许通过插件替换就是另一回事了。

snowpack

snowpack 是一个相对轻量的 bundless 方案,之前也写过一篇 精读 snowpack,其实 bundless 就是利用浏览器支持的 ESM import 特性,利用浏览器进行模块间依赖加载,而不需要在编译时进行。

跳过编译时依赖加载可以省很多事,比如不用考虑 tree shaking 问题,也不用为了最终产物加速而使用缓存,相当于这些工作交给最终执行的浏览器了,而浏览器作为最终运行时容器,比编译时工具更了解应该如何按需加载。

仅从编译时来看,修改单个文件的编译速度与项目整体大小有关,而若不考虑整体项目,仅编译单个文件(最多递归一下有限的依赖模块,解决比如 TS 类型变量判断问题)时间复杂度一定是 O(1) 的。

实际上我们很少单独使用 snowpack,因为其编译使用的 esbuild 还未达到 1.0 稳定版本,在生态兼容与产物稳定性上存在风险,所以编译打包时往往采用 rollup 或 webpack,但这种割裂也导致了开发与生产环境不一致,这往往代表着更大的风险,因此在 vite 框架可以看到这块的取舍。

snowpack 是开箱即用的:

// package.json
"scripts": {
  "start": "snowpack dev",
  "build": "snowpack build"
},

我们还可以增加 snowpack.config.js 配置文件开启 remote 模式:

// snowpack.config.js
module.exports = {
  packageOptions: {
    "source": "remote",
  }
};

remote 模式是 Streaming Imports,即不用安装对应的 npm 包到本地,snowpack 自动从 skypack 读取文件并缓存起来。

snowpack 看起来更多是对 bundless 纯粹的尝试,而不是一个适合满足日常开发的工具,因为日常开发需要一个一站式工具,这就是后面说的 vite 与 wmr。

vite

可以理解为结合了 snowpack 特色的一站式构建工具,从开发到发布全套流程都帮你搞定。

涉及的用法非常多,具体内容可以看 官方文档

与 snowpack 不同的是,snowpack 生产打包的产物是独立的文件,而 vite 没有采用 esbuild 而是 rollup 打包,目的是为了打包为一个整体,并规避 esbuild 不稳定的风险。

另外由于 vite 集成化更高,比 snowpack 多了许多功能,比如 css 拆分、多页、使用 esbuild 进行依赖预构建、monorepo 支持、对多框架支持、SSR 等等。具体可以看 文档介绍。然而原文说这有利有弊,好处是开箱即用,弊端是缺乏定制的灵活性。

其实革命性突破主要是 bundless,在这基础上发展出一系列便捷的功能,这值得每一个工程化团队学习。其实就算决定再造一个轮子,也是维持 90% 功能不变的基础上,在默认的偏好设置做一些微调,而这些大多可以用 插件 解决。

总结下来,Vite 是一个既积极拥抱新特性,又为生产环境考虑的工程化全家桶,相比之下,技术栈过于前沿的工具只能称为玩具,而 Vite 是真的可以用一用的。

wmr

由 preact 作者开发,可以理解为 preact 版的 vite。所以对于 preact 技术栈的开发者更加友好,集成度更高。

原文提到的另一个特色是,wmr 使用了 htm 转换 JSX,使其获得了更加精确的报错体验,即可以精确到源码行的同时指定到具体列。

综合功能和 vite 差不多,单页 + ssr 都支持,如果你平时使用 preact,或者想开发一个体积极小的项目,可以考虑用 wmr 全家桶。

总结

新一代前端构建工具最大特色有两个:更底层的语言编写、bundless,如果用一个词描述就是高性能。积极拥抱浏览器新特性或者知识跨界都可以帮助前端领域取得新的突破。

另外构建工具已经变得越来越集成化,从仅用于编译的 esbuild,到支持开发的 snowpack,再到内置了最佳实践、甚至支持比如 ssr 等后端能力、最后到垂直场景的 vitePress,每抽象一次,都更开箱即用,但带来的灵活性降低也成为各团队自己造轮子的理由,越上层越是有自己造轮子的冲动。

这和可视化领域很像,可视化从最底层的 svg、canvas、webgl 到基于其封装的命令式框架,再到数据驱动开发框架、完全 JSON 配置化的图表库、甚至到零配置,根据数据猜配置的智能化项目,也是配置越来越少,但灵活度越来越低,使用什么层次的完全看项目对细节的要求。

不过工程化相对还是标准化的,因为可视化面向的是用户,而工程化面向的是程序员,我们不能控制用户需求,但可以控制程序员的开发习惯

最后,除了升级你的构建工具外,换一台 M1 芯片电脑也可以极大提升开发效率,笔者亲测 webpack 构建速度提升 3 倍!

本文作者:前端小毛

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!