其他
2022 前端工具链十年盘点
Editor's Note
The following article is from Alibaba F2E Author 黄炎(承虎)
作 者|黄炎(承虎)
文章来源 | Alibaba F2E
2021 的年度盘点我们选择了一个特别的形式,把时间范围拉长到 10 年,梳理前端工具链里的 12 个重要的包的发布和版本更新时间,结合 npm 下载数据,看看前端的工具链在这十年间有怎样的演变。
查看本图细节 请访问:https://time.graphics/line/598790
前史:2009 - 2010
2009 年前,前端的工具链不由 JavaScript 编写,功能也较为简单,如 make、python、C# 等。2009 年起,前端工具链的前置要求被逐个满足。
模块定义:2009 年,CommonJS 模块定义规范被提出;
语言:2009 年,ECMAScript 5 发布,JavaScript 标准更明确,功能更多;
执行环境:2009 年,Node.js 发布初始版本;
包管理:2010 年,npm 发布;
第一章:寻找抽象,2011 - 2015
任务:2012 年 Grunt 发布首版¹²,将处理过程定义为多个不同的任务,每个任务执行一个函数或插件;
文件流:2013 年 Gulp 发布首版,并快速在同年发布到了 3.0 正式版,在 Grunt 抽象任务的基础上,Gulp 引入了流编程的概念,避免在执行复杂任务时,需要将编译中间结果放在临时文件夹的场景;
模块依赖:2012 年 Webpack 发布首版,并于 2014 年发布 1.0 正式版,它通过分析模块间依赖来决定编译过程,将可扩展点抽象为 loader 和 plugin。
Node.js 支持:2011 年,browserify 发布首版,允许在前端仓库引入 Node.js 的部分 API,并实现跟其他库类似的打包步骤;
国内前端开发:2013 年,百度开源了 FIS,针对国内前端的更常见需求进行了支持,包括 GBK 特性支持;
转译:2014 年,Babel 发布首版³,重心放在对 JavaScript 转译,使得尚在提案阶段的语言特性能兼容。
注 1:部分包在发版 npm 前,会通过官网直接分发,本文所有包发版时间以 npm 为准,不统计其他渠道,下略。 注 2:“首版”即 npm 包首次发版时间,它可能小于 1.0.0,下略。 注 3:Babel 首版叫做 6to5,后改名为 Babel。
第二章:打包一切,2016 - 2019
高封装性:即配置内容简单,不需要写太多配置即可完成前端流程配置;
低复杂度:即工具的内部实现简单,文档友好度、插件书写复杂度均受此特性影响;
强能力:即支持的功能集更多。
2013 年⁴,Parcel 发布首版,并在 2018 年发布 1.0 正式版,在当时它主打无配置启动项目;
2015 年,Rollup 发布首版,并在 2019 年发布 1.0 正式版,它主打工具库的打包,相比 Webpack 配置更简单和轻量;
面临其他工具库的挑战,Webpack 也在 2018 年发布 4.0 版,支持了无配置启动项目。
注 4:从 npm 记录而言,Parcel 首版发布于 2013 年,但是它大规模进入公共视野是在 2017 年。
第三章:性能优化,2020 至今
2020 年,Webpack 5.0 发布,实现了多进程编译以优化计算密集型任务,并强化了缓存机制;
2020 年,Snowpack 发布首版正式版,主打不打包项目依赖的模块(Bundleless),而是直接依赖 CDN 提供的模块文件,大大提升了本地环境运行速度;
2020 年,Vite 发布首版,同样主打 Bundleless。
CPU 密集型,如压缩、转译等环节,可能的优化有:
使用更高效算法:优化空间小;
压榨 V8 性能:如参考 Crankshaft Bailout 或 TurboFan Bailout;
多核并行计算:受到进程通信开销制约;
使用其他语言实现⁵:受到跨语言通信制约;
I/O 密集型,包括:
文件读写:利用 bundleless 减少本地文件读取量;此外 Node.js 默认异步 API 使得此类任务能足够快,优化空间小;
进程通信:序列化/反序列化开销较大,共享内存的 worker_threads 尚不稳定⁶,此外线程启动有损耗;
跨语言通信:2018 年,napi-rs 1.0 发布,Node.js 调用 rust 有了更高效简单的方式⁷;
GPU 密集型,前端场景较少⁸,包括:
机器学习:如使用 NVIDIA RAPIDS API 的 node-rapids;
图像处理:如 GPU.js。
2019 年,基于 Rust 实现的 SWC 发布首版,对标 Babel,显著提升了性能;
2020 年,使用 go 实现的 esbuild 发布首版,相比 SWC 更聚焦于 TypeScript 和 JavaScript 的转译,性能更快;
2020 年,Vite 发布 2.0,使用 esbuild 实现了性能二次提升;
2020 年,Parcel 发布 2.0,基于 napi-rs 和 Rust 重新实现;
2020 年,rome 发布首版,在 2021 年也转为基于 Rust 开发。
Babel 14 亿,稳坐榜首;
Webpack 8亿,位列其次;
新兴的高性能打包降序依次是:esbuild 4800万、Vite 860万、Parcel 340万、SWC 280万、Snowpack 170万;
老牌的打包工具降序依次是:Rollup 2亿、Gulp 720万、Grunt 350万。
注 5:JavaScript 的特性为 JIT、弱类型、动态类型,其执行效率相对其他 AOT、强类型、静态类型的语言更低。 注 6:Node 12 起正式支持 worker_threads,但稳定性一直不高,如触发 Access Violation。 注 7:对于 Rust,一开始有 neon 提供 js binding,但性能还不够快。 注 8:因为 Node.js 标准包里不包含对 GPU 的封装。另外,浏览器缺乏直接利用 GPU 的 API,直到 WebGPU 出现。
CommonJS 溯源:https://arstechnica.com/information-technology/2009/12/commonjs-effort-sets-javascript-on-path-for-world-domination/
JavaScript 二十年:https://github.com/doodlewind/jshistory-cn
npm 包发版时间:https://libraries.io/
npm 包下载数据:https://npm-stat.com/charts.html