Skip to main content
Bun 的打包器支持 --compile 标志,用于从 TypeScript 或 JavaScript 文件生成独立的二进制可执行文件。
terminal
cli.ts
这会将 cli.ts 打包成一个可以直接运行的可执行文件:
terminal
所有导入的文件和包都会被打包进可执行文件中,同时包含一份 Bun 运行时。所有内置的 Bun 和 Node.js API 都被支持。

跨平台交叉编译

使用 --target 标志,可以将独立可执行文件编译为与运行 bun build 的机器不同的操作系统、架构或 Bun 版本。 构建 Linux x64 版本(大多数服务器):
terminal
构建 Linux ARM64 版本(例如 Graviton 或 Raspberry Pi):
terminal
构建 Windows x64 版本:
terminal
为 Windows arm64 构建:
terminal
构建 macOS arm64 版本:
terminal
构建 macOS x64 版本:
terminal

支持的目标平台

--target 值的各个部分可以按任意顺序出现,只要它们使用 - 分隔即可。
在 x64 平台上,Bun 使用需要 CPU 支持 AVX2 指令的 SIMD 优化。Bun 的 -baseline 版本适用于不支持这些指令的旧款 CPU。Bun 安装程序会检测应使用哪个版本,但进行交叉编译时,你可能不知道目标 CPU 的具体情况。这主要影响 Windows x64 和 Linux x64,在 Darwin x64 上则很少遇到。如果你或你的用户看到 "Illegal instruction" 错误,可能需要使用 baseline 版本。

编译时常量

使用 --define 标志可将编译时常量注入可执行文件,例如版本号、构建时间戳或配置值:
terminal
Bun 会在构建时将这些常量内联到二进制文件中,因此它们不会产生任何运行时开销,并且能够实现死代码消除。
如需了解更多示例和模式,请参阅构建时常量指南

生产环境部署

编译后的可执行文件降低内存使用并提升 Bun 启动速度。 通常情况下,Bun 会在 importrequire 时读取并转译 JavaScript 和 TypeScript 文件。这正是 Bun 能够“开箱即用”的原因之一,但这并非没有代价:从磁盘读取文件、解析路径、解析代码、转译以及打印源代码都会消耗时间和内存。 编译后的可执行文件将这些开销从运行时转移到了构建时。 部署到生产环境推荐做法:
terminal

字节码编译

为提升启动速度,启用字节码编译:
terminal
使用字节码编译,tsc 启动速度提升两倍:
字节码性能比较
字节码编译将大文件的解析开销从运行时转移到打包时,提升了启动速度,但稍微增加了 bun build 命令的时长,不影响源码可读性。
字节码编译在搭配 --compile 时同时支持 cjsesm 格式。

各个标志的作用

--minify 参数会减小转译后输出代码的大小。对于大型应用,这可以节省数兆字节的空间。对于较小的应用,它仍可能略微改善启动时间。 --sourcemap 参数会嵌入使用 zstd 压缩的源映射,这样错误和堆栈跟踪就会指向其原始位置,而不是转译后的位置。发生错误时,Bun 会自动解压并解析源映射。 --bytecode 参数会启用字节码编译。每次在 Bun 中运行 JavaScript 代码时,JavaScriptCore(引擎)都会将源代码编译为字节码。--bytecode 会将这部分解析工作从运行时转移到打包时,从而缩短启动时间。

嵌入运行时参数

--compile-exec-argv="args" - 嵌入运行时参数,可在运行时通过 process.execArgv 获取:
terminal
app.ts

通过 BUN_OPTIONS 传入运行时参数

独立可执行文件会读取 BUN_OPTIONS 环境变量,因此你可以无需重新编译即可传入运行时标志:
terminal

自动加载配置

独立可执行文件可以自动从运行目录加载配置文件。默认:
  • 禁用 加载 tsconfig.jsonpackage.json — 这些通常只在开发时需要,编译时已经用过了
  • 启用 加载 .envbunfig.toml — 这些通常包含运行时配置,部署时可能有所不同
未来版本中,为了更确定的行为,可能会默认禁用 .envbunfig.toml 加载。

运行时启用配置加载

如果您的可执行文件需要在运行时读取 tsconfig.jsonpackage.json,请使用以下标志启用:
terminal

运行时禁用配置加载

要禁用 .envbunfig.toml 以实现确定性执行:
terminal

作为 Bun CLI 使用

此功能自 Bun v1.2.16 起支持
设置 BUN_BE_BUN=1 环境变量,可以将独立可执行文件作为 bun CLI 本身运行。该可执行文件会忽略其打包的入口点,转而提供完整的 bun CLI。 例如,考虑一个由以下脚本编译而成的可执行文件:
terminal
通常,使用参数运行 ./such-bun 时,会执行该脚本。
terminal
但是,使用 BUN_BE_BUN=1 环境变量后,它的行为就会像 bun 二进制文件一样:
terminal
基于 Bun 构建的 CLI 工具可以利用此功能来安装软件包、打包依赖项或运行其他文件,而无需下载单独的二进制文件或安装 Bun。

全栈可执行文件

此功能自 Bun v1.2.17 起支持
--compile 标志可以创建一个同时包含服务器和客户端代码的独立可执行文件,非常适合全栈应用。当你在服务器代码中导入 HTML 文件时,Bun 会将前端资源(JavaScript、CSS 等)打包并嵌入可执行文件中。
构建为单个可执行文件:
terminal
生成的独立二进制包含:
  • 你的服务器代码
  • Bun 运行时
  • 所有前端资源(HTML、CSS、JavaScript)
  • 服务器用到的所有 npm 包
最终生成的是一个单独的文件,你可以将其部署到任何地方,而无需安装 Node.js、Bun 或任何依赖项:
terminal
Bun 会使用正确的 MIME 类型和缓存标头提供前端资源。HTML 导入会被替换为一个清单对象,Bun.serve 会使用该对象提供预先打包的资源。 有关构建全栈应用的更多信息,请参阅全栈指南

Worker

使用独立可执行文件中的 Worker,需要将 Worker 入口也加入构建:
terminal
然后在代码中这样引用 Worker:
index.ts
向独立可执行文件添加多个入口时,每个入口都会分别打包到可执行文件中。 我们最终可能会自动检测 new Worker(path) 中静态已知的路径并将其自动打包,但目前你需要将 Worker 文件列为入口,就像前面的示例一样。 如果你使用相对路径指向未包含在独立可执行文件中的文件,Bun 会相对于进程当前工作目录从磁盘加载该路径;如果文件不存在,则会报错。

SQLite

使用 bun:sqlite 导入时,支持 bun build --compile 默认情况下,数据库文件路径相对进程当前工作目录。
index.ts
这意味着,如果可执行文件位于 /usr/bin/hello,且用户的终端当前位于 /home/me/Desktop,Bun 会查找 /home/me/Desktop/my.db
terminal

嵌入静态资源及文件

独立可执行文件可以直接将文件嵌入二进制文件中,因此单个可执行文件就可以携带应用程序所需的图像、JSON 配置、模板或其他资源。

机制原理

使用 with { type: "file" } 导入属性来嵌入文件:
index.ts
此导入返回路径字符串,指向嵌入文件。构建时 Bun 会:
  1. 读取文件内容
  2. 将数据嵌入可执行文件
  3. 将导入替换为内部路径(以 /$bunfs/ 为前缀)
你可以通过 Bun.file() 或 Node.js 的 fs API 读取嵌入文件。

用 Bun.file() 读取嵌入文件

Bun.file() 是读取嵌入文件的推荐方式:
index.ts

用 Node.js fs 读取嵌入文件

嵌入文件可以与 Node.js 文件系统 API 一起使用:
index.ts

实践示例

嵌入 JSON 配置

index.ts

HTTP 服务器中提供静态资源

用 Bun.serve() 的 static 路由高效提供静态文件:
server.ts
Bun 会自动处理静态路由的 Content-Type 头和缓存策略。

嵌入模板文件

index.ts

嵌入二进制文件

index.ts

嵌入 SQLite 数据库

要将 SQLite 数据库嵌入编译后的可执行文件,请在导入属性中设置 type: "sqlite",并将 embed 属性设置为 "true" 数据库文件必须已存在于磁盘。然后在代码中导入:
index.ts
最后编译为独立可执行文件:
terminal
构建时数据库文件必须存在。embed: "true" 告诉打包器将数据库内容内嵌进可执行文件。常规运行 bun run 时数据库文件仍从磁盘加载。
在编译后的可执行文件中,嵌入的数据库为读写模式,但所有更改会在程序退出时丢失(内存存储)。

嵌入 N-API 插件

可将 .node 文件嵌入可执行文件:
index.ts
如果使用 @mapbox/node-pre-gyp 或类似工具,必须直接 require .node 文件,否则无法正确打包。

嵌入目录

使用 --asset(或 JavaScript API 中的 compile.assets)将文件或目录树嵌入可执行文件,并保留其原始相对路径。嵌入的文件在运行时位于 import.meta.dir 下,并且可以通过 node:fsexistsSyncstatSyncreaddirSyncreadFileSync)和 Bun.file() 访问。
terminal
index.ts
多次传递 --asset 可嵌入多个目录(例如,对于 SvelteKit 构建,可以使用 --asset ./client --asset ./prerendered)。只有普通文件会被嵌入;目录树中的符号链接和空子目录会被跳过。 你也可以通过将单个文件添加为额外入口点,以旧方式嵌入文件;导入的资源会根据 --asset-naming 重命名(默认为 [name]-[hash].[ext]):

运行时检测独立模式

使用 Bun.isStandaloneExecutable 来检查当前进程是否正在从编译后的二进制文件运行:
index.ts
Bun.embeddedFiles.length > 0 不同,这种检查不会为每个嵌入文件分配 Blob 对象,因此即使二进制文件嵌入了大量资源,也可以安全地在启动时调用。

列出嵌入文件

Bun.embeddedFiles 将所有嵌入文件以 Blob 对象的形式公开:
index.ts
Bun.embeddedFiles 中每个元素是带 name 属性的 Blob
可以使用它通过 static 路由提供所有嵌入的资源:
server.ts
Bun.embeddedFiles 不含源码文件(.ts.js 等)以保护源码。

内容哈希

默认情况下,嵌入文件的名称会附加内容哈希,这有助于通过 URL 或 CDN 提供文件时实现缓存失效。若要保留原始名称,请配置资源命名方式:
terminal

代码压缩(Minification)

启用代码压缩以减少可执行文件体积:
terminal
Bun 使用自身压缩器来减小代码体积。不过总体上 Bun 的二进制仍然偏大,未来还会优化。

Windows 平台特有标志

在 Windows 上编译独立可执行文件时,平台特定选项可以自定义生成的 .exe 文件的元数据:
terminal
Windows 可用选项说明:
  • icon - 指定 .ico 图标文件路径
  • hideConsole - 隐藏后台终端窗口(GUI 应用用)
  • title - 可执行文件属性中的应用标题
  • publisher - 发布者名称
  • version - 版本号字符串
  • description - 描述信息
  • copyright - 版权声明
除了 hideConsole 之外,这些标志不能在交叉编译时使用,因为它们依赖 Windows API。

macOS 代码签名

为独立可执行文件进行代码签名以消除 Gatekeeper 警告,使用 codesign 命令:
terminal
推荐附带带有 JIT 权限的 entitlements.plist 文件:
info.plist
使用 --entitlements 标志来支持 JIT 权限:
terminal
签名后验证:
terminal
代码签名支持需要 Bun v1.2.4 及以上版本。

代码拆分

独立可执行文件支持代码拆分。结合 --compile--splitting 可生成带有运行时动态加载代码拆分块的可执行文件。
terminal
运行编译结果:
terminal
输出:

使用插件

插件与独立可执行文件协同工作;使用它们在构建期间转换文件:
build.ts
使用场景示例 — 构建时嵌入环境配置:
cli.ts
插件可以执行任何转换:编译 YAML/TOML 配置、内联 SQL 查询、生成类型安全的 API 客户端,或预处理模板。请参阅插件文档

不支持的 CLI 参数

--compile 标志不支持以下标志:
  • --outdir — 请改用 outfile
  • --public-path
  • --target=node
  • --target=browser(不含 HTML 入口点 — 对于使用 .html 文件的 --compile --target=browser,请参阅独立 HTML
  • --no-bundle - Bun 始终会将所有内容捆绑到可执行文件中。

API 参考

Bun.build() 中的 compile 选项支持三种形式:
类型
用法示例:

支持的目标

Bun.Build.CompileTarget

完整示例

build.ts