构建系列之新一代利器 Esbuild(上)
What is Esbuild?
Esbuild 是由 Figma 的 CTO 「Evan Wallace」基于 Golang 开发的一款打包工具,相比传统的打包工具,主打性能优势,在构建速度上可以快 10~100 倍。
为什么会这么快?
go 实现,编译为本地代码
大多数打包器都是用 JavaScript 编写的,esbuild 采用 Go 语言开发,相比于 单线程 + JIT 性质的解释型语言 ,使用 Go 的优势在于 :
一方面可以充分利用多线程打包,并且线程之间共享内容,而 JS 如果使用多线程还需要有线程通信(postMessage)和序列化数据的开销;
另一方面直接编译成机器码,而不用像 Node 一样先将 JS 代码解析为字节码,然后转换为机器码,大大节省了程序运行时间。
垃圾回收,go 的堆线程之间共享,javascrit 是每个 js 线程独享一个堆。
多核并行
内部打包算法充分利用多核 CPU 优势。Esbuild 内部算法设计是经过精心设计的,尽可能充分利用所有的 CPU 内核。所有的步骤尽可能并行,这也是得益于 Go 当中多线程共享内存的优势,而在 JS 中所有的步骤只能是串行的。具体来说:解析
和代码生成
是大部分工作,并且能够齐全并行化
(链接在大多数状况下是固有的串行工作)。
极致的代码
esbuild 通过自行实现所有逻辑来避免第三方库带来的性能问题, 统一的数据结构可以减少数据转换开销, 并且可以根据需要改变架构, 当然最大的缺点就是工作量倍增.
**内存高效利用 **
ESBuild 在实现时尽量减少数据的传递以及数据的转换, ESBuild 尽量减少了对整体 AST 的传递, 并且尽可能复用 AST 数据, 其他的 Bundler 可能会在编译的不同阶段往复转换数据格式(string -> TS -> JS -> older JS -> string...,这其中会涉及复杂的编译工具链,比如 webpack -> babel -> terser,每次接触到新的工具链,都得重新解析 AST). 在内存存储效率方面 Go 也比 JavaScript 更高效.
劣势
其实也不能说是劣势,更准确地说 Esbuild 本身的限制,每个构建工具都有自己的初衷,而在更完美地实现这个目标的同时也会在一些方面做取舍:
没有 TS 类型检查
不能操作 AST,这个确实会带来一些不便之处,很多大型项目都会有操作 AST 的需要,所以就需要引入 babel 插件解决
不支持装饰器语法
产物 target 无法降级到 ES5 及以下,意味着需要 ES5 产物的场景只用 Esbuild 无法胜任
垂直场景
对于前端的构建工具来说主要有这样几个垂直的功能:
Bundler
Transformer
Minimizer
Esbuild 作为 transformer 性能是可以的,但 Esbuild 兼容性不足,可以不优先考虑。
Esbuild 作为 Bundler 已经被 Vite 作为开发阶段的依赖预打包工具,同时也被大量用作线上 esm CDN 服务,比如 esm.sh 等等;作为 Minimizer ,Esbuild 也已足够成熟,目前已经被 Vite 作为 JS 和 CSS 代码的压缩工具用上了生产环境。
插件机制
esbuild 插件就是一个对象,里面有 name 和 setup 两个属性,name 是插件的名称,setup 是一个函数,其中入参是一个 build 对象,这个对象上挂载了一些钩子可供我们自定义一些构建逻辑。以下是一个简单的 esbuild 插件示例:
总结
本篇文章主要围绕着 esbuild 的强大性能做介绍,快是它最大的利器,所谓天下武功唯快不破的道理大家懂得都懂,我们也是从底到上的分析了 esbuild 快的原因,下半部分主要围绕着 esbuild 的使用场景为切入点,欢迎期待。微信公众号首发,欢迎关注,转发,评论。
版权声明: 本文为 InfoQ 作者【江湖修行】的原创文章。
原文链接:【http://xie.infoq.cn/article/758a7faa1a97b65c7efd8c12a】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论