esbuild 比 Webpack、Rollup 快 10–100 倍,核心在于用 Go 重写以消除 JS 运行时开销,采用单二进制交付、全阶段内存复用、原生并发及现代语法深度特化,放弃兼容旧标准以换取极致性能。

esbuild 能做到比 Webpack、Rollup 快 10–100 倍,核心不靠算法优化,而在于用对了语言、绕开了 JS 生态的固有瓶颈。
用 Go 重写,彻底摆脱 JavaScript 运行时开销
Webpack 和 Rollup 都基于 Node.js(V8 引擎),即使代码再精简,也要承担垃圾回收、事件循环调度、动态类型检查、JS 对象内存分配等运行时成本。esbuild 用 Go 编写,直接编译为静态二进制,启动零延迟,无解释执行,函数调用、字符串处理、AST 遍历全部走原生机器码路径。例如解析一个 5MB 的 TypeScript 文件,Go 的 UTF-8 字符串切片比 JS 的 substring 快 3–5 倍,且无需拷贝底层内存。
- 单线程性能高:Go 的 goroutine 调度器让并发解析/转换互不阻塞,实际打包中常以 10+ goroutine 并行处理不同文件
- 内存更可控:没有 V8 堆内存抖动,大项目下 RSS 内存稳定在 200–400MB,而同等场景 Webpack 常突破 1.5GB
全阶段内存复用,避免 AST 多次序列化
传统构建工具通常“解析 → 生成 AST → 序列化为 JS 对象 → 转换插件遍历 → 生成新 AST → 打印代码”,每步都涉及深拷贝和对象创建。esbuild 把整个流程压在一个内存视图里:源码读入后,词法分析器直接产出 token slice;语法分析器复用同一块字节缓冲区构造节点指针;所有 transform(如 JSX、TS 类型擦除)只修改节点标记位或局部字段,不新建 AST 树;最后打印器直接按偏移量拼接原始字节片段。
- 不生成完整 AST 对象树:节点是结构体数组索引,不是 JS 的
{ type: 'CallExpression', arguments: [...] } - Source map 生成与代码打印同步进行,不额外遍历 AST
零依赖 + 单二进制交付,消除模块加载与解析延迟
esbuild 没有 node_modules,不走 CommonJS require 或 ESM import 链路。它的全部逻辑(lexer、parser、resolver、bundler、minifier)都静态链接进一个约 12MB 的二进制中。启动时直接 mmap 加载,省去 Node.js 解析数百个 JS 文件、构建模块图、处理 package.json exports 字段的时间。实测 cold start(首次运行)耗时约 3ms,而 Webpack 在相同机器上需 300ms+ 仅用于加载自身依赖。
立即学习“Java免费学习笔记(深入)”;
- resolver 使用前缀哈希表加速路径查找,
import 'react'不查node_modules/react/package.json,直接定位到预埋的入口路径 - 支持
--watch时,文件变更通过 inotify/kqueue 原生监听,响应在毫秒级,不依赖 chokidar 等 JS 层封装
面向现代 JS 特性做深度特化,不做通用妥协
esbuild 明确放弃支持老旧语法(如 ES5 的 for...in with Proxy 陷阱)、不实现完整的 TypeScript 类型检查、不兼容 UMD 或 SystemJS 输出格式。它专注处理 ES2015+、JSX、CSS-in-JS、JSON imports 等高频现代用例,并为它们写出极致内联汇编级优化路径。比如可选链 a?.b.c 的转译,esbuild 直接生成带 label 的 if-else 字节码序列,而非抽象成通用 helper 函数。
- Tree-shaking 基于控制流图(CFG)而非作用域分析,能安全剔除死分支中的导出引用
- Minify 阶段与打包合并:变量重命名、常量折叠、IIFE 提取全部在同一个 pass 完成,不跨阶段通信
它快,是因为从第一天就决定不兼容旧世界,也不迁就 JS 生态的协作范式——用系统级语言、内存视角、场景特化,重新定义“构建”这件事的本质。


















