构建系列之新一代利器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 无法胜任

插件机制

esbuild 插件就是一个对象,里面有name和setup两个属性,name是插件的名称,setup是一个函数,其中入参是一个 build 对象,这个对象上挂载了一些钩子可供我们自定义一些构建逻辑。以下是一个简单的esbuild插件示例:

let envPlugin = {
		name: 'env',
		setup(build) {
			// 文件解析时触发     // 将插件作用域限定于env文件,并为其标识命名空间"env-ns"     build.onResolve({ filter: /^env$/ },
			args => ({
				path: args.path,
				namespace: 'env-ns',
			}))
		// 加载文件时触发     // 只有命名空间为"env-ns"的文件才会被处理     
		// 将process.env对象反序列化为字符串并交由json-loader处理     
		build.onLoad({
			filter: /.*/,
			namespace: 'env-ns'
		}, () => ({
			contents: JSON.stringify(process.env),
			loader: 'json',
		}))
	},
}
require('esbuild')
	.build({
			entryPoints: ['app.js'],
			bundle: true,
			outfile: 'out.js', 
// 应用插件
   plugins: [envPlugin], })
.catch(() => process.exit(1))

使用如下:

*// 应用了env插件后,构建时将会被替换成process.env对象*  
import { PATH } from 'env'  
console.log(`This is ${PATH}`)

插件实现的时候需注意:Esbuild 插件机制只可作用于 build API,而不适用于 transformAPI,这意味着 webpack 当中的 esbuild-loader 这种只使用 Esbuild transform 功能的地方无法利用 Esbuild 的插件机制。 

场景

对于前端的构建工具来说主要有这样几个垂直的功能:

  • Bundler

  • Transformer

  • Minimizer

Esbuild作为 transformer 性能是可以的,但 Esbuild 兼容性不足,可以不优先考虑。

Esbuild 作为 Bundler 已经被 Vite 作为开发阶段的依赖预打包工具,同时也被大量用作线上 esm CDN 服务,比如esm.sh等等;作为 Minimizer ,Esbuild 也已足够成熟,目前已经被 Vite 作为 JS 和 CSS 代码的压缩工具用上了生产环境。

总结

本篇文章主要围绕着esbuild的强大性能做介绍,快是它最大的利器,所谓天下武功唯快不破的道理大家懂得都懂,我们也是从底到上的分析了esbuild快的原因,下半部分主要围绕着esbuild的使用场景为切入点,欢迎期待。微信首发,欢迎关注微信公众号:江湖修行,感谢各位老铁。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值