Bun

单文件可执行文件

Bun 的捆绑器实现了一个 --compile 标志,用于从 TypeScript 或 JavaScript 文件生成一个独立的二进制文件。

bash
cli.ts
bun build ./cli.ts --compile --outfile mycli
cli.ts
console.log("Hello world!");

这会将 cli.ts 捆绑到一个可直接执行的可执行文件中

$ ./mycli
Hello world!

所有导入的文件和包都捆绑到可执行文件中,以及 Bun 运行时的副本。支持所有内置的 Bun 和 Node.js API。

交叉编译到其他平台

--target 标志允许你为与运行 bun build 的机器不同的操作系统、架构或 Bun 版本编译你的独立可执行文件。

为 Linux x64(大多数服务器)构建

bun build --compile --target=bun-linux-x64 ./index.ts --outfile myapp

# To support CPUs from before 2013, use the baseline version (nehalem)
bun build --compile --target=bun-linux-x64-baseline ./index.ts --outfile myapp

# To explicitly only support CPUs from 2013 and later, use the modern version (haswell)
# modern is faster, but baseline is more compatible.
bun build --compile --target=bun-linux-x64-modern ./index.ts --outfile myapp

为 Linux ARM64(例如 Graviton 或 Raspberry Pi)构建

# Note: the default architecture is x64 if no architecture is specified.
bun build --compile --target=bun-linux-arm64 ./index.ts --outfile myapp

为 Windows x64 构建

bun build --compile --target=bun-windows-x64 ./path/to/my/app.ts --outfile myapp

# To support CPUs from before 2013, use the baseline version (nehalem)
bun build --compile --target=bun-windows-x64-baseline ./path/to/my/app.ts --outfile myapp

# To explicitly only support CPUs from 2013 and later, use the modern version (haswell)
bun build --compile --target=bun-windows-x64-modern ./path/to/my/app.ts --outfile myapp

# note: if no .exe extension is provided, Bun will automatically add it for Windows executables

为 macOS arm64 构建

bun build --compile --target=bun-darwin-arm64 ./path/to/my/app.ts --outfile myapp

为 macOS x64 构建

bun build --compile --target=bun-darwin-x64 ./path/to/my/app.ts --outfile myapp

支持的目标

--target 标志的顺序无关紧要,只要它们以 - 分隔即可。

--target操作系统架构现代基线
bun-linux-x64Linuxx64
bun-linux-arm64Linuxarm64N/A
bun-windows-x64Windowsx64
bun-windows-arm64Windowsarm64
bun-darwin-x64macOSx64
bun-darwin-arm64macOSarm64N/A

在 x64 平台上,Bun 使用 SIMD 优化,该优化需要支持 AVX2 指令的现代 CPU。Bun 的 -baseline 构建适用于不支持这些优化的旧 CPU。通常,当您安装 Bun 时,我们会自动检测要使用哪个版本,但由于您可能不知道目标 CPU,因此在交叉编译时可能更难做到这一点。您通常不必担心 Darwin x64,但它与 Windows x64 和 Linux x64 相关。如果您或您的用户看到 "Illegal instruction" 错误,您可能需要使用基准版本。

部署到生产环境

编译的可执行文件减少了内存使用量并缩短了 Bun 的启动时间。

通常,Bun 在 importrequire 时读取和转换 JavaScript 和 TypeScript 文件。这是 Bun “正常工作” 的一部分,但它不是免费的。从磁盘读取文件、解析文件路径、解析、转换和打印源代码需要时间和内存。

使用编译的可执行文件,您可以将该成本从运行时转移到构建时。

在部署到生产环境时,我们建议执行以下操作

bun build --compile --minify --sourcemap ./path/to/my/app.ts --outfile myapp

这些标志有什么作用?

--minify 参数优化了转换后输出代码的大小。如果您有一个大型应用程序,这可以节省数兆字节的空间。对于较小的应用程序,它可能仍然会稍微缩短启动时间。

--sourcemap 参数嵌入了使用 zstd 压缩的源代码映射,以便错误和堆栈跟踪指向其原始位置,而不是转换后的位置。当发生错误时,Bun 会自动解压缩和解析源代码映射。

SQLite

您可以将 bun:sqlite 导入与 bun build --compile 一起使用。

默认情况下,数据库相对于进程的当前工作目录进行解析。

import db from "./my.db" with { type: "sqlite" };

console.log(db.query("select * from users LIMIT 1").get());

这意味着如果可执行文件位于 /usr/bin/hello,用户的终端位于 /home/me/Desktop,它将查找 /home/me/Desktop/my.db

$ cd /home/me/Desktop
$ ./hello

嵌入资产和文件

独立的可执行文件支持嵌入文件。

要使用 bun build --compile 将文件嵌入到可执行文件中,请在代码中导入该文件

// this becomes an internal file path
import icon from "./icon.png" with { type: "file" };
import { file } from "bun";

export default {
  fetch(req) {
    // Embedded files can be streamed from Response objects
    return new Response(file(icon));
  },
};

可以使用 Bun.file 的函数或 Node.js 的 fs.readFile 函数(在 "node:fs" 中)来读取嵌入的文件。

例如,要读取嵌入文件的内容

import icon from "./icon.png" with { type: "file" };
import { file } from "bun";

const bytes = await file(icon).arrayBuffer();

嵌入 SQLite 数据库

如果您的应用程序想要嵌入 SQLite 数据库,请在 import 属性中设置 type: "sqlite",并将 embed 属性设置为 "true"

import myEmbeddedDb from "./my.db" with { type: "sqlite", embed: "true" };

console.log(myEmbeddedDb.query("select * from users LIMIT 1").get());

此数据库是可读写的,但当可执行文件退出时,所有更改都将丢失(因为它存储在内存中)。

嵌入 N-API 插件

从 Bun v1.0.23 开始,您可以将 .node 文件嵌入到可执行文件中。

const addon = require("./addon.node");

console.log(addon.hello());

不幸的是,如果您使用 @mapbox/node-pre-gyp 或其他类似工具,则需要确保直接需要 .node 文件,否则它将无法正确捆绑。

缩小

要稍微减小可执行文件的大小,请将 --minify 传递给 bun build --compile。这使用 Bun 的缩小器来减小代码大小。不过,总体而言,Bun 的二进制文件仍然太大,我们需要使其更小。

不支持的 CLI 参数

目前,--compile 标志一次只能接受一个入口点,并且不支持以下标志

  • --outdir — 改用 outfile
  • --splitting
  • --public-path
  • --target=node--target=browser
  • --format - 始终输出二进制可执行文件。在内部,它几乎是 esm。
  • --no-bundle - 我们始终将所有内容捆绑到可执行文件中。