esbuild
1. 定义
esbuild 是一个用 Go 写的 JavaScript / TypeScript 打包器 (bundler) + 编译器 (transpiler),把一堆源码模块合并、转译、压缩成浏览器或 Node 能直接跑的产物。 最大卖点:极快——比 webpack / rollup 快 10~100 倍,靠 Go 的原生多线程并行编译实现。
类比:esbuild 之于打包,相当于 ripgrep 之于搜索——同样的活,用编译型语言重写一遍,快出一个数量级。很多现代工具(Vite、tsup)底层就是调 esbuild。
2. esbuild 解决了什么问题
传统 JS 打包器(webpack、rollup)用 JavaScript 自己写,单线程、慢:
| 问题 | webpack / rollup | esbuild |
|---|---|---|
| 打包速度 | 大项目冷启动几十秒起 | 通常亚秒级 |
| 语言实现 | JS(单线程、有 GC 开销) | Go(原生多线程并行) |
| TS 转译 | 需 ts-loader / babel | 内置,直接吃 .ts |
| 配置复杂度 | 配置项极多、心智负担重 | API 精简,几个选项就能用 |
痛点:前端项目越大,webpack 越慢,改一行代码等半天。esbuild 把”转译 + 打包 + 压缩”用 Go 重写并行化,速度碾压。
注意定位:esbuild 追求快,牺牲了一部分功能完整度(如复杂的代码分割、类型检查)。它常被当作底层引擎,而非全功能替代 webpack。
3. 核心概念
- Bundle(打包):把入口文件及其所有
import依赖递归合并成一个(或几个)输出文件 - Transpile(转译):把 TS / JSX / 新语法 (ES2022) 降级成目标环境能跑的 JS。注意:esbuild 只做语法转换,不做类型检查(类型错误照样打包成功,类型检查得靠
tsc --noEmit) - Minify(压缩):删空格、缩短变量名、去死代码,减小体积
- Loader:告诉 esbuild 怎么处理不同后缀文件(
.ts、.jsx、.css、.png等) - Target:输出目标(
es2017、chrome58、node18…),决定语法降级到什么程度 - Platform:
browser(默认)/node/neutral,影响模块解析和内置全局变量
4. 常用命令
CLI 基础
esbuild app.ts --bundle --outfile=out.js # 打包成单文件
esbuild app.ts --bundle --minify --outfile=out.js # 打包 + 压缩
esbuild app.ts --bundle --sourcemap # 生成 sourcemap
esbuild app.ts --bundle --watch # 监听变化自动重打包常用选项
--bundle # 开启打包(否则只转译单文件)
--minify # 压缩
--sourcemap # 生成 .map 便于调试
--target=es2017 # 语法降级目标
--platform=node # 面向 Node(默认 browser)
--format=esm # 输出模块格式:esm / cjs / iife
--outdir=dist # 输出到目录(多入口时用)
--external:react # 把某个包排除,不打进产物(运行时再提供)
--loader:.png=dataurl # 指定某后缀的加载方式通过 npx 临时用(不全局装)
npx esbuild app.ts --bundle --outfile=out.jsJS API 方式(更常见于脚本 / 构建工具里)
// build.mjs
import * as esbuild from "esbuild";
await esbuild.build({
entryPoints: ["src/app.ts"],
bundle: true,
minify: true,
sourcemap: true,
target: ["es2020"],
platform: "browser",
outfile: "dist/app.js",
});node build.mjs5. esbuild vs webpack vs rollup vs Vite 速查
| 维度 | webpack | rollup | esbuild | Vite |
|---|---|---|---|---|
| 语言 | JS | JS | Go | JS(底层用 esbuild + rollup) |
| 速度 | 慢 | 中 | 极快 | 快(dev 用 esbuild) |
| 定位 | 全功能应用打包 | 库打包 | 极速转译/打包引擎 | 现代前端开发工具 |
| 代码分割 | 强 | 强 | 基础 | 强(靠 rollup) |
| TS 类型检查 | 靠 loader | 靠插件 | 不做 | 不做(需 tsc) |
| 插件生态 | 最丰富 | 丰富 | 较少 | 丰富 |
| 典型用途 | 传统大型应用 | 发布 npm 库 | 底层引擎 / 简单打包 | 现代 SPA 开发 |
关键认知:Vite 开发模式底层就是用 esbuild 做超快转译,生产构建才切到 rollup。esbuild 更多是”被其他工具使用的引擎”。
6. 典型工作流
打包一个 Node CLI 工具成单文件
esbuild src/cli.ts --bundle --platform=node --target=node18 --outfile=dist/cli.js打包前端库(排除 peer 依赖)
esbuild src/index.ts --bundle --format=esm --external:react --external:react-dom --outfile=dist/index.js配合类型检查(esbuild 不查类型,得分开做)
tsc --noEmit # 先单独做类型检查
esbuild src/app.ts --bundle --outfile=dist/app.js # 再打包7. 常见坑
- 不做类型检查:TS 类型错误 esbuild 照样打包通过。CI 里必须另跑
tsc --noEmit,否则类型 bug 会漏到生产 - 代码分割能力有限:复杂的 chunk 拆分、动态 import 优化不如 rollup/webpack,做大型应用产物优化时可能不够用
- CSS / 静态资源处理基础:能处理但功能简单,复杂场景(CSS Modules、图片压缩)要靠插件或换工具
--bundle忘了加:不加只做单文件转译,import不会被合并进来,运行时报找不到模块--platform用错:给 Node 打包却用默认browser,会导致require/内置模块解析异常- 装饰器 / 某些 TS 特性:
emitDecoratorMetadata等依赖类型信息的特性 esbuild 不支持,需要用 tsc 或 swc
8. 延伸阅读 / 关联概念
- Vite — 现代前端构建工具,dev 阶段底层就是 esbuild,最常见的 esbuild 使用场景
- tsup — 基于 esbuild 的库打包工具,配置更简单,专门打 npm 包
- swc — 同样用编译型语言(Rust)写的 JS/TS 转译器,和 esbuild 定位相近,是竞品
- Bun — 内置的
bun build也是极速打包器,思路类似;见bun.md - rollup / webpack — 功能更全的传统打包器,esbuild 常和它们互补而非完全替代
- 官方文档:https://esbuild.github.io/