两条关键的线索
谈到前端构建工具,我们能想到常用的webpack、vite。不妨多想一步,它们是如何发展和壮大的呢?未来又是怎样的走向?
对于构建工具的发展,我总结了两个关键的线索,模块化和构建性能。
线索一:模块化
JavaScript模块化的发展,是构建工具变迁的重要因素。
有了CommonJS,才有Browserify/Webpack这种将众多 CommonJS 模块组合到一个 bundle 中的构建工具。
有了ESM标准,才有Rollup的出现,Webpack也跟着支持了ESM模块。随着浏览器大量支持ESM,才有了Vite。
线索二:构建性能
Web项目越来越大,对于构建性能的要求也越来越高。只使用JavaScript编写的构建工具不能满足性能要求,所以出现了SWC、esbuild等其他语言编写的构建工具。
模块化的发展
为了方便我们更好的梳理构建工具的发展脉络,先简单回顾一下模块化的发展路径。
IIFE
IIFE(Immediately Invoked Function Expression,即"立即调用函数表达式")是一种 JavaScript 编程模式,用于创建一个立即执行的函数。这种模式常用于隔离作用域,避免变量污染全局命名空间。
最早知道这个语法是从jquery中看到的。基本语法如下:
javascript
(function() {
// jquery的代码在这里执行
})();
// 在页面中通过script代码块引用
<script src="jquery.js"></script>
局限:当页面中引入很多的js脚本,并且这些脚本有依赖关系要使用彼此的功能时,这种模块方式很难支持。
AMD
AMD(Asynchronous Module Definition,即"异步模块定义")是一种用于定义和加载模块的 JavaScript 模块化规范。它主要用于浏览器环境,旨在解决模块化和异步加载的问题。
RequireJS 是 AMD 规范的一个流行实现。它提供了一个简单的 API 来加载和管理模块,并支持配置和优化。
javascript
// 定义一个模块
define('math', [], function() {
return {
add: function(x, y) {
return x + y;
}
};
});
// 使用模块
require(['math'], function(math) {
console.log(math.add(2, 3)); // 输出: 5
});
局限:当我们要管理大量的依赖时,直接开发符合AMD规范的代码也是相当麻烦的。
CommonJS
CommonJS 是一种用于 JavaScript 的模块化规范,最初是为了在服务器端环境(如 Node.js)中使用而设计的。它提供了一种简单而有效的方式来组织和管理代码,使得开发者可以将代码分割成独立的模块,提升代码的可维护性和重用性。
javascript
// math.js
function add(x, y) {
return x + y;
}
function subtract(x, y) {
return x - y;
}
module.exports = {
add,
subtract
};
javascript
// main.js
const math = require('./math');
console.log(math.add(5, 3)); // 输出: 8
console.log(math.subtract(5, 3)); // 输出: 2
ESM
ESM(ECMAScript Modules)是 JavaScript 的官方模块系统,作为 ECMAScript 2015(ES6)的一部分引入。ESM 提供了一种标准化的方式来定义和使用模块,使得 JavaScript 在浏览器和服务器端环境中都能更好地进行模块化开发。
javascript
// math.js
export function add(x, y) {
return x + y;
}
export function subtract(x, y) {
return x - y;
}
// 或者使用默认导出
export default function multiply(x, y) {
return x * y;
}
javascript
// main.js
import { add, subtract } from './math.js';
import multiply from './math.js';
console.log(add(5, 3)); // 输出: 8
console.log(subtract(5, 3)); // 输出: 2
console.log(multiply(5, 3)); // 输出: 15
它的静态结构和异步加载特性使得代码更容易管理和优化。随着浏览器和 Node.js 对 ESM 的广泛支持,ESM 已成为前端和后端开发的主流选择。
Webpack和它的对手们
一个故事总有一个主角,即使是《权力的游戏》这样的群像剧也有个大男主,我们这个故事的大男主就是Webpack,我准备围绕它来叙述构建工具们的诞生与发展。
Browserify
第一个出场的角色是Browserify。于2011 年发布。注意这个时间点,CommonJS于2009 年随着Node.js第一个版本发布。两年后出现了Browserify。
Browserify 旨在将 Node.js 风格的 CommonJS 模块打包成可以在浏览器中运行的代码。在浏览器环境下,JavaScript 原本并不支持 CommonJS 模块系统,因此需要像 Browserify 这样的工具来桥接这两个环境的差异。
局限:Browserify虽然完成的打包的任务,但是没有很好的支持代码分割和异步加载。
Webpack登场
于是乎,我们的主角登场了(2012 年),它不但可以将众多 CommonJS 模块组合到一个 bundle 中,还对代码分割、动态加载和热模块替换等进行了很好的支持(这些功能在现代 Web 开发中变得越来越重要)。大大的提升了构建体验。
Webpack没有止步不前。 2017 年 1 月,Webpack 2 引入了对 ES6 模块( ESM在2015年提出,也就是ECMAScript 2015(也称为 ES6)中引入)的原生支持,并改进了代码拆分和 Tree Shaking 功能。2017 年 6 月,这个版本引入了 Scope Hoisting,以提高打包后的代码执行性能。
Parcel:第一个反派
Webpack此时有个比较大的问题就是配置繁琐,此时它迎来了人生中的第一个大反派,Parcel。
2017 年 11 月,Parcel发布了第一个版本,主打的就是零配置。吸引了许多开发者的关注。
Webpack的反击
2018 年 2 月,Webpack 4 发布。这个版本中Webpack给出了自己的回击。也提升了配置体验。
Webpack 4 带来了显著的性能改进,并引入了零配置模式(mode),开发者可以选择开发模式或生产模式。此外,还增加了对 WebAssembly 的支持。
Rollup:又一个对手
Rollup的打法是专注于 ES 模块打包。显然这种打法为自己争夺了一块领土,在前端构建工具的世界中拥有了自己的一块领土。
Rollup 的最初版本是在 2015 年发布的。在后续不断发展壮大,后续被Vite招入麾下。
Rollup诞生
回到模块化发展的线索:IIFE -> AMD -> CommonJS -> ESM。
随着ESM模块化的发布,如同当初Browserify专注于将 CommonJS 模块打包以供浏览器使用。自然要出现专注于ES Module(ESM)的打包工具,即Rollup。Rollup 利用 ESM 的静态分析能力来进行高级优化,如 tree-shaking,这在构建库和应用时非常有用。
虽然Webpack有这很大的市场,但是Rollup同样也有一席之地。
Vite:新一季的主角
时间来到2020年,Webpack还在精进自我,发布了第5个版本,这个版本引入了持久化缓存、模块联邦(Module Federation)、改进的 Tree Shaking 和更好的 WebAssembly 支持。此时的Webpack已是构建工具领域真正的王者。
但这个国度从来不缺乏挑战者,随着浏览器对ESM的支持越来越好,新的角色闪亮登场。
Snowpack
真正的主角出现之前,往往会出现一个疑似主角的人,它就是Snowpack。
2020年初发布了Snowpack。旨在通过利用原生 ES 模块(ESM)来加速开发过程。Snowpack 的设计初衷是减少开发时的构建时间,通过在浏览器中直接使用 ES 模块,从而避免了传统打包工具的复杂性和性能瓶颈。
Vite
Snowpack没有笑到最后,这个世界有了一个更好的工具Vite。同样是借助于浏览器对于ESM的广泛支持,Vite专注于提升开发体验。并在之后逐渐壮大,在后续的版本中逐渐完善自己。
- Vite 1.0- 发布于 2020 年 6 月。Vite 1.0 引入了即时的模块热替换和快速的开发服务器,专注于提升开发体验。
- Vite 2.0- 发布于 2021 年 2 月。Vite 2.0 带来了对多种框架(如 Vue、React、Preact、Svelte 等)的更好支持,以及对 Rollup 插件生态系统的兼容性。
- Vite 3.0- 发布于 2022 年 7 月。Vite 3.0 提升了性能,改进了插件系统,并更新了许多默认配置以支持更广泛的使用场景。
- Vite 4.0- 发布于 2023 年 6 月。Vite 4.0 继续优化性能,增加了对新的 JavaScript 和 CSS 特性的支持,并改善了开发和构建体验。
Vite和esbuild、rollup之间的关系
俗话说团结就是力量,Vite选择了两个弟兄帮助自己成为好用的工具。
- 开发阶段:在开发模式下,Vite 使用 ESBuild 来处理 JavaScript 和 TypeScript 的转换。这是因为 ESBuild 以极高的速度编译代码,能够显著提升开发体验。ESBuild 的快速处理能力使得 Vite 可以实现即时模块热更新(HMR),让开发者在修改代码时几乎立即看到变化。
- 生产构建阶段:在生产环境下,Vite 使用 Rollup 作为打包工具。Rollup 是一个成熟的打包工具,擅长处理 ES 模块,拥有丰富的插件生态和强大的优化能力。
Vite结合了 ESBuild 和 Rollup 的优势:在开发阶段利用 ESBuild 的速度,在生产阶段利用 Rollup 的优化能力。
小结
紧随着线索一,随着模块化的发展,产出了诸多构建工具,其中的佼佼者Webpack和Vite脱颖而出。但是构建工具的王国还存在一个重大的挑战,也就是线索二说的事,前端项目越来越大越来越复杂,性能问题一直困扰着前端开发者们,我们急需性能强大的构建工具。
新的挑战:构建性能
在这个篇章里,首先向我们走来的是SWC和esbuild。
SWC:Babel的替代者
SWC(Speedy Web Compiler)是一个用 Rust 编写的 JavaScript/TypeScript 编译器,旨在提供快速的编译速度和高效的代码转换。它的主要目标是替代 Babel 等传统 JavaScript 编译器,提供更快的性能,特别是在大型项目中。
2017 年kdy1 开始写 SWC。
2021 年,kdy1 加入了 Vercel 团队,SWC 也成了 Next.js 的默认转译器。
如果我们的项目使用的Webpack,可以考虑使用swc-loader来提升构建速度。
总结:SWC归根结底只是一个编译器,并不能整体解决构建性能的问题,我们期待一些大角色。
esbuild:为解决性能瓶颈而生
2020 年初,Evan Wallace开始开发这个项目。esbuild 是用 Go 编写的,这使得它在编译速度上非常快。
目前被vite纳入麾下,作为开发环境的构建工具。
缺陷:esbuild 非常快,但是对构建资源优化的控制非常有限,并且插件API不够灵活;
从目前的苗头看,esbuild也不是真正的版本之子,还得看看其他工具可以成为本季的新主角。
Turbopack:Webpack作者的新儿子
Turbopack是由Webpack的创建者Tobias Koppers和Next.js团队使用Rust语言开发的,由 Vercel 于 2022 年 10 月首次发布。它的主要目标是取代Webpack,成为下一代前端构建工具。Turbopack的设计理念是提供极快的构建速度和开发体验。
这里Rust成为了引领前端基建的宠儿,Turbopack就是用Rust编写。
可以想到Webpack作者已然明白在旧的Webpack上已经没有性能优化的余地,需要使用Rust开新坑,用全新的工具解决性能问题,至于在未来能获得多少开发者的青睐,让我们拭目以待吧。
Rolldown:Vite的痛点与解决之道
Vite 的痛点在发布时就存在,即它的两个兄弟。
- esbuild 非常快,但是对构建资源优化的控制非常有限,并且插件API不够灵活;
- Rollup 成熟且灵活,但与本地打包工具相比仍然较慢,并且ESM/CJS互操作的处理还有待改进。
所以,如果能有一个具有本地速度和 Rollup 的灵活性的打包工具,那太好了。它就是Rolldown。
Vite 团队正在研发 Rolldown,它是使用 Rust 开发的 Rollup 替代品。最终,Rolldown 的目标并不是取代现有的工具,而是更好地满足在 Vite 中所面临的独特需求,并最终使所有使用 Vite 的用户受益。
Rspack:字节人想出的新办法
这里重点引入了Rspack官网上与turbopack的不同的说法。在我看来它两个是同一层次的竞品。
与 turbopack 不同的是,Rspack 选择了对 webpack 生态兼容的路线,一方面,这些兼容可能会带来一定的性能开销,但在实际的业务落地中,我们发现对于大部分的应用来说,这些性能开销是可以接受的,另一方面,这些兼容也使得 Rspack 可以更好地与上层的框架和生态进行集成,能够实现业务的渐进式迁移。
React和Vue的脚手架们
这里还要花一个小篇幅来说一下脚手架们,我们知道编写一个项目,不止有构建工作,还有些必要的初始化工作,这就需要脚手架了。脚手架也理所当然的要集成构建工具。
Create React App
Create React App(CRA)是一个由 Facebook 开发的命令行工具,用于快速创建和设置 React 应用程序的项目结构。内置了Webpack。
Vue CLI
用于构建vue项目。也是内置了Webpack的脚手架,现在已经不推荐使用,因为vue使用了Vite。
create-vue
用于构建vue项目。帮助构建基于Vite的Vue项目脚手架。
总结
故事现在看来还远远没有完结,2025年,让我们持续关注它们的新进展吧。希望在未来有更好用、性能更优异的构建工具为我们开发者使用。