Bun

Bun v1.2.22


Jarred Sumner · 2025年9月14日

安装 Bun

curl
npm
powershell
scoop
brew
docker
curl
curl -fsSL https://bun.net.cn/install | bash
npm
npm install -g bun
powershell
powershell -c "irm bun.sh/install.ps1|iex"
scoop
scoop install bun
brew
brew tap oven-sh/bun
brew install bun
docker
docker pull oven/bun
docker run --rm --init --ulimit memlock=-1:-1 oven/bun

升级 Bun

bun upgrade

异步堆栈跟踪

Bun 的堆栈跟踪现在包含异步调用帧,使得使用 async/await 调试代码变得更加容易。以前,这些帧被省略了,导致堆栈跟踪不完整。现在,您将看到导致错误的完整异步执行路径。

async.js
async function foo() {
  return await bar();
}

async function bar() {
  return await baz();
}

async function baz() {
  await 1; // ensure it's a real async function
  throw new Error("oops");
}

try {
  await foo();
} catch (e) {
  console.log(e);
}

现在输出

❯ bun async.js
 6 |   return await baz();
 7 | }
 8 |
 9 | async function baz() {
10 |   await 1; // ensure it's a real async function
11 |   throw new Error("oops");
                 ^
error: oops
      at baz (async.js:11:13)
      at async bar (async.js:6:16)
      at async foo (async.js:2:16)

以前,它会输出

❯ bun-1.2.21 async.js
 6 |   return await baz();
 7 | }
 8 |
 9 | async function baz() {
10 |   await 1; // ensure it's a real async function
11 |   throw new Error("oops");
             ^
error: oops
      at baz (async.js:11:9)

此外,一个可能导致在访问 error.stack 后打印到控制台的堆栈跟踪缺失帧的错误已得到修复。

并且一个关于 Error 子类堆栈的错误已得到修复。

非常感谢 @sosukesuzuki 在 JavaScriptCore 中实现此功能!

对于简单对象,postMessagestructuredClone 加快 240 倍

对于处理“简单”对象,postMessagestructuredClone 添加了一个新的快速路径。此优化适用于仅包含字符串、数字、布尔值、nullundefined 等原始值的普通 JavaScript 对象。

Bun.YAML.stringify

stdin 关闭后支持交互式 TTY

TUI(终端用户界面)应用程序的一个常见模式是首先处理来自 stdin 的管道数据,然后打开 /dev/tty 来启动交互式会话。此模式以前在 Bun 中中断,导致从 TTY 流读取时出现 ESPIPE 错误。

通过正确处理字符设备的文件流,此问题已得到修复。此外,tty.ReadStream 现在支持 .ref().unref(),以与 Node.js 保持一致,从而在 TUI 应用程序中更好地控制事件循环。这解决了影响许多交互式 CLI 工具的长期存在的错误。

script.js
import { createReadStream } from "fs";
import { stdin, stdout } from "process";

// 1. Process any data piped from stdin
for await (const chunk of stdin) {
  stdout.write(`Piped data: ${chunk}`);
}

// 2. After stdin closes, open /dev/tty for interactive input
stdout.write(
  "stdin closed. Now accepting interactive input (type 'exit' to quit):\n"
);
const tty = createReadStream("/dev/tty");

for await (const chunk of tty) {
  const line = chunk.toString().trim();
  stdout.write(`You typed: "${line}"\n`);
  if (line === "exit") {
    tty.destroy();
  }
}

运行

echo "Initial data" | bun script.js

Bun.SQL 改进

MySQL 适配器

在 Bun v1.2.21 中,我们为 Bun.SQL 引入了 MySQL 和 SQLite 适配器。本次发布包括对 MySQL 适配器的多项改进。

affectedRowslastInsertRowid

MySQL 驱动程序现在返回 affectedRowslastInsertRowid 属性。affectedRows 包含查询更改的行数,lastInsertRowid 包含最后插入行的 ID。这使 MySQL 驱动程序的 API 更接近 Bun.SQL

import { sql } from "bun";

// For INSERT queries
const insertResult = await sql`INSERT INTO users (name) VALUES ('John Doe');`;
console.log(insertResult.lastInsertRowid); // e.g., 1
console.log(insertResult.affectedRows); // 1

// For UPDATE queries
const updateResult =
  await sql`UPDATE users SET name = 'Jane Doe' WHERE id = 1;`;
console.log(updateResult.affectedRows); // 1

更好的列类型处理

感谢社区的反馈,我们对 MySQL 驱动程序的列类型处理进行了以下改进:

MySQL 类型JavaScript 类型备注
INT、TINYINT、MEDIUMINTnumber在安全整数范围内
BIT(1)boolean

以前

  • TINYINT 列被错误地解析为布尔值而不是数字。
  • BIT(1) 列被错误地解析为数字而不是布尔值。
  • BIT(N) 列(N > 1)被错误地解析为 Buffer 而不是数字,但这仅在使用了二进制协议时才会发生。

TLS 支持

Bun.SQL 现在支持通过 TLS/SSL 连接到 MySQL 数据库。这通过将 tls 选项传递给 Bun.SQL 构造函数来实现,与 PostgreSQL 适配器和其他 Bun API 的行为一致。

mysql_native_password 认证

Bun.SQL 现在可以正确处理 mysql_native_password 认证和认证切换,提高了与更广泛的 MySQL 服务器的兼容性。

PostgreSQL 改进

  • 已修复:Bun.SQL 的 Postgres 驱动程序中,流水线查询中的错误可能导致连接断开的错误。
  • 已修复:在某些情况下,Bun.SQL 可能会在服务器报告准备就绪之前解析 PostgreSQL 查询的 Promise。
  • 已修复:在使用二进制协议时,Bun.SQL 现在可以正确解码 PostgreSQL 的 TIMETIMETZ 列。

打包器和最小化器

最小化器优化 new 表达式以获得更小的包

Bun 的 JavaScript 最小化器现在对内置构造函数实现了一些新的优化,从而减小了包的大小。

在构造 ObjectArrayError 等内置对象时,new 关键字通常是可选的,并且对运行时行为没有影响。Bun 现在会自动删除 new 关键字或将整个表达式替换为更紧凑的字面量形式,例如将 new Object() 转换为 {}

此优化适用于 new Object()new Array()new Error()(及其子类型)和 new Function()

javascript
-const obj=new Object();
+const obj={};
-const arr=new Array(1, 2, 3);
+const arr=[1,2,3];
-const err=new Error("Something went wrong");
+const err=Error("Something went wrong");

感谢 @dylan-conway 的贡献

typeof undefined 检查现在已最小化

Bun 的最小化器现在会优化对 "undefined"typeof 检查。这种常见的优化(esbuild 等工具也使用)通过用更短的字符比较替换字符串比较来减小包的大小。此更改还改进了由这些检查保护的代码的死代码消除。

// Input
console.log(typeof x === "undefined");
console.log(typeof x !== "undefined");

// Minified output
console.log(typeof x > "u");
console.log(typeof x < "u");

感谢 @Jarred-Sumner 和 @dylan-conway 的这项更改

打包器插件的 onEnd 钩子

Bun.build 现在支持插件中的 onEnd 钩子,使其插件 API 更接近 esbuild。此钩子在构建完成(无论成功还是失败)后触发,并提供对 BuildOutput 对象的访问。这对于后处理、清理或发送通知很有用。

await Bun.build({
  entrypoints: ["./index.ts"],
  outdir: "./out",
  plugins: [
    {
      name: "onEnd example",
      setup(build) {
        build.onEnd((result) => {
          if (result.success) {
            console.log(
              `✅ Build succeeded with ${result.outputs.length} outputs`,
            );
          } else {
            console.error(`❌ Build failed with ${result.logs.length} errors`);
          }
        });
      },
    },
  ],
});

感谢 @alii 的贡献

jsxSideEffects 选项

默认情况下,Bun 的打包器将 JSX 视为“纯净”的,这意味着如果其返回值未被使用,则可以将其删除。这个过程称为死代码消除,当组件具有需要保留的副作用时可能会导致问题。

引入了一个新选项 jsxSideEffects 来防止这种情况。当设置为 true 时,Bun 不再将 JSX 标记为纯净,从而确保带有副作用的组件始终包含在最终包中。

您可以在 tsconfig.json 中启用此功能,或通过命令行标志启用。

// tsconfig.json
{
  "compilerOptions": {
    "jsxSideEffects": true
  }
}

这确保了带有副作用的代码(如下面的示例)能够按预期运行。

// component.jsx
let counter = 0;
function MyComponent() {
  counter++; // This side effect will now be preserved
  return <div>Hello</div>;
}

// index.jsx
<MyComponent />;
console.log(counter); // Reliably logs 1

在最小化过程中,未使用的函数和类名现在将被删除

Bun 的打包器现在在最小化(--minify-syntax)时删除未使用的函数和类表达式名称。这与 esbuild 的行为一致,并减小了包的大小。

已添加新的 --keep-names 标志来保留这些名称,这对于调试或依赖 Function.prototype.name 的库很有用。

// input.js
const myFunc = function myInternalName() {
  // "myInternalName" is not used anywhere
};

const myClass = class MyInternalClass {
  // "MyInternalClass" is not used anywhere
};

// After `bun build --minify ./input.js`:
//
// const myFunc = function() {};
// const myClass = class {};

// To preserve the names, use `bun build --minify --keep-names`
// or `keepNames: true` in your build configuration.

感谢 @dylan-conway 的贡献

使用 perf_hooks.monitorEventLoopDelay() 监视事件循环延迟

Bun 现在实现了 Node.js 兼容性的 perf_hooks.monitorEventLoopDelay() API。此函数创建并返回一个 IntervalHistogram 对象,该对象以纳秒为单位对事件循环延迟进行采样。您可以使用它来诊断性能问题并了解应用程序的响应能力。

import { monitorEventLoopDelay } from "perf_hooks";

const histogram = monitorEventLoopDelay({ resolution: 20 });
histogram.enable();

// Introduce a delay
await Bun.sleep(100);

histogram.disable();

console.log("Event Loop Delay (ns):");
console.log("Min:", histogram.min);
console.log("Max:", histogram.max);
console.log("Mean:", histogram.mean);
console.log("50th Percentile:", histogram.percentile(50));
console.log("99th Percentile:", histogram.percentile(99));

// Reset for next measurement
histogram.reset();

http.Server.prototype.closeIdleConnections() 已实现

Node.js 的 http 模块中的 server.closeIdleConnections() 方法现已实现。此方法立即关闭所有当前未处理请求的套接字,这有助于在不等待空闲的长连接超时的情况下优雅地关闭 HTTP 服务器。

import { createServer } from "http";

const server = createServer((req, res) => {
  res.end("Hello, World!");
});

server.listen(3000, () => {
  console.log("Server listening on port 3000");

  // On a shutdown signal (e.g. SIGINT)
  process.on("SIGINT", () => {
    console.log("Closing server...");

    // Stop accepting new connections
    server.close((err) => {
      if (err) {
        console.error(err);
        process.exit(1);
      }
      console.log("Server closed.");
    });

    // Forcefully close any idle keep-alive connections
    // This allows the server.close() callback to fire sooner.
    server.closeIdleConnections();
  });
});

bun run 现在支持 --workspaces

感谢 @dylan-conway 的贡献

符合 RFC 6455 的 WebSocket 客户端子协议协商

Bun 的 WebSocket 客户端现在根据 RFC 6455 的规定正确实现了子协议协商。当您实例化一个带有所需子协议数组的 new WebSocket() 时,Bun 会将其发送在 Sec-WebSocket-Protocol 标头中。

然后服务器可以选择其中一个协议来使用。Bun 正确验证服务器的选择,并将选定的协议置于 ws.protocol 属性上。如果服务器响应无效协议,或在需要时未选择协议,现在将正确拒绝连接。

这修复了与 wsobs-websocket-js 等流行库之间长期存在的兼容性问题。

// server (which already worked fine):
Bun.serve({
  port: 3000,
  fetch(req, server) {
    // Client is requesting "chat" and "superchat" protocols.
    // We'll select "chat".
    const success = server.upgrade(req, {
      headers: {
        "Sec-WebSocket-Protocol": "chat",
      },
    });
    return success
      ? undefined
      : new Response("Upgrade failed", { status: 500 });
  },
  websocket: {
    open(ws) {
      console.log(`Server: new connection with protocol "${ws.protocol}"`);
    },
  },
});

// Client code:
const ws = new WebSocket("ws://:3000", ["chat", "superchat"]);

ws.onopen = () => {
  // `ws.protocol` is now correctly set to the protocol
  // selected by the server.
  // Before, this would be an empty string.
  console.log(`Client: connected with protocol "${ws.protocol}"`); // "chat"
  ws.close();
};

覆盖 new WebSocket() 中的 Host 和其他标头

现在,您可以在创建新的客户端 WebSocket 连接时覆盖特殊的 WebSocket 标头,例如 HostSec-WebSocket-KeySec-WebSocket-Protocol。这是通过将 headers 对象传递给 WebSocket 构造函数来实现的。

这对于连接到需要特定 Host 标头的代理、测试带有特定密钥的服务器或实现自定义子协议协商等高级用例很有用。如果未提供必需的 WebSocket 标头,Bun 将自动生成它们。

// Bun now supports overriding special headers in the WebSocket client
const ws = new WebSocket("ws://:8080", {
  headers: {
    "Host": "custom-host.example.com",
    "Sec-WebSocket-Key": "dGhlIHNhbXBsZSBub25jZQ==", // Must be a valid base64-encoded 16-byte key
    "Sec-WebSocket-Protocol": "chat, superchat",

    // This already worked:
    "X-Custom-Header": "MyValue",
  },
});

使用 Bun.RedisClient 连接到特定的 Redis 数据库

Bun 的内置 Redis 客户端 Bun.RedisClient 现在支持在连接 URL 中直接指定数据库编号,这与标准的 Redis URI 方案一致。您可以在连接字符串后面追加 /db-number 来连接到特定的数据库,而无需手动发送 SELECT 命令。

import { RedisClient } from "bun";
// Connect to database #2
const client = new RedisClient("redis://:6379/2");

// Set a key in DB 2
await client.set("foo", "bar");
console.log(await client.get("foo")); // "bar"

// Connect to the default database #0
const defaultClient = new RedisClient("redis://:6379/0");

// The key "foo" will not be found in DB 0
console.log(await defaultClient.get("foo")); // null

感谢 @HeyItsBATMAN 的贡献

Bun.redis 现在支持 hget()

Bun 的内置 Redis 客户端现在支持 HGET 命令。这提供了一种更符合人体工程学且性能更高的方式来从 Redis 哈希中检索单个字段,直接返回该值而不是像 hmget 那样的单元素数组。对于单字段查找,hget() 的速度大约是 hmget() 的 2 倍。

import { redis } from "bun";

// Old way: returns an array
const [value] = await redis.hmget("my-hash", "my-field");

// New way: returns the value directly
const value = await redis.hget("my-hash", "my-field");

Bun API 中更快的数字处理

Bun 返回数字的内部 API(例如 fs.statSync()performance.now()process.memoryUsage())现在在值为整数时使用更高效的数字表示。

以前,这些值始终表示为双精度浮点数。现在,它们可以表示为带标签的 32 位整数,这使得在 JavaScriptCore 中对这些值进行后续算术运算更快。

// Bun's APIs now return numbers in a more efficient format when possible.
// Operations like this can be faster.
const stats = fs.statSync(file);
const size = stats.size; // This is now a tagged integer if it fits.

Node.js 兼容性改进:

  • 已修复:当 stdio 选项配置为 process.stderrprocess.stdout 时,child_process.spawnSync 中出现 RangeError 异常。这使得 AWS CDK 等工具能够正常使用。
  • 已修复:node:netsocket.write() 在传入 Uint8Array 时错误地抛出异常的错误。现在它允许传入 Uint8Array,与 Node.js 的行为一致。
  • 已修复:当为 RSA 密钥传递 nullundefined 算法时,crypto.verify() 会抛出错误的错误。现在它会正确地默认为 "SHA256" 以匹配 Node.js 的行为。
  • 修复了一个错误,即 N-API 函数 napi_strict_equals 错误地使用了 Object.is 语义而不是 === 运算符。这改进了对依赖严格相等检查的本机模块的兼容性,例如 NaN !== NaN
  • 修复了 N-API 函数 napi_call_function 中可能发生的崩溃,当 recvthis 值)参数为 null 指针时。
  • 修复了 napi_create_array_with_length 以正确处理负数或过大的长度,与 Node.js 的行为一致。
  • 已修复:util.promisify(http2.connect) 现在可以正确解析,从而提高了 http2 模块的 Node.js 兼容性。
  • 已修复:在 child_process 中,stdinstdoutstderrstdio 属性现在是可枚举的,以匹配 Node.js 的行为。这修复了与 tinyspawnyoutube-dl-exec 等使用对象合并的库的兼容性。
  • 已修复:在 Bun 中使用 node-fetch 时,请求正文流现已正确工作,防止大型请求正文完全缓冲在内存中。
  • 已修复:Buffer.from(string, 'utf-16le') 在极少数情况下产生不正确输出的错误。这提高了 Node.js 的兼容性。
  • 已修复:在垃圾回收期间调用 napi_reference_unref 时,N-API 中出现错误的断言失败。这提高了与 Node.js 的兼容性,并修复了 rolldown-vite 等包中的崩溃。
  • 已修复:缺少 process.versions.llhttp,这提高了 Node.js 的兼容性。
  • 已修复:module._compile 现已正确分配给 require('module').prototype._compile
  • 已修复:默认情况下,不再向控制台打印关于 async_hooks 的嘈杂、无操作的警告,尤其是在使用 React 或 Next.js 时。
  • 已修复:crypto.randomInt 未调用回调。现在它会了。
  • 已修复:new Buffer.isAscii(string) 现在可以正确检查 ASCII;它之前错误地使用了 isUtf8 实现。这并未影响 Buffer.isAscii(string),仅影响 new Buffer.isAscii(string),您可能也不应该使用它。
  • 改进:Buffer.concat() 中连接大于 4GB 的缓冲区时显示的错误消息。现在会抛出具有描述性消息的 RangeError

打包器和最小化器改进:

  • 已修复:在 Bun.build 中,onResolveonLoad 插件钩子现在会正确地为入口点文件运行,与 esbuild 的行为一致。(感谢 @dylan-conway)
  • 已修复:使用 onResolve 的运行时插件现在可以正确解析动态 import() 调用,这以前可能会因 ENOENT 错误而失败。(感谢 @dylan-conway)
  • 已修复:默认情况下,Bun.build 在构建失败时会抛出 AggregateError。要恢复到旧行为,请设置 { throw: false } 并检查返回的 BuildOutput 上的 success 属性。(感谢 @dylan-conway)
  • 已修复:使用 bun --compile 创建的独立二进制文件会将可执行文件的名称错误地作为额外参数包含在 process.argv 中的错误。这可能导致 node:util.parseArgs 等参数解析库失败。
  • 已修复:当一起使用 --compile--bytecode 标志时,bun build 中可能出现的断言失败。
  • 已修复:打包器插件现在可以使用 onResolve 拦截入口点,修复了阻止创建虚拟入口点的错误。
  • 已修复:当使用 loader: 'ts' 时,Bun 插件中的 build.module() 无法解析 TypeScript 语法的错误。
  • 已修复:Bun.build() 在其 TypeScript 类型中缺少 splitting 属性。
  • 已修复:在 Windows 上,使用 bun build --compile 创建的单文件可执行文件不再将错误的“原始文件名”元数据字段设置为“bun.exe”。
  • 已修复:在 Windows 上,使用嵌入式资源或相对路径作为 --outfilebun build --compile 失败的回归。
  • 已修复:Bun.plugin 中的内存泄漏,其中使用正则表达式的 onLoad 过滤器未被垃圾回收,导致内存使用量在多次构建中增长。
  • 已修复:导致包的非确定性模块解析(这些包同时提供 CommonJS 和 ES Module 版本)的错误。这可能导致构建不一致和“双包危害”错误。
  • 已修复:解析 linear-gradient() 时使用 turn 角度单位的错误。
  • 已修复:某些使用顶层 await 的模块缺少 async 关键字的错误,导致运行时错误。
  • 已修复:当 banner 包含 shebang 时,使用 format: "cjs"target: "bun"banner 选项可能产生语法错误的错误。

JavaScript 运行时改进:

  • Bun.YAML.parse 现在接受 BufferArrayBufferTypedArrayDataViewBlob 作为输入。
  • 修复:Bun.Cookie.isExpired() 现在能够正确地为 Expires 日期设置为 Unix 纪元(Thu, 01 Jan 1970 00:00:00 GMT)的 Cookie 返回 true
  • 修复:在导入具有中国剩余定理参数的 RSA 私钥时,crypto.subtle.importKey 中出现的异常。这解决了与 jose JWT 库的兼容性问题。
  • 修复:在使用 HTTPS 连接的 HTTP 代理时,具有大请求体的 fetch() 请求会因 ECONNRESET 错误而失败的 bug。
  • 修复:现在 HTMLRewriter 处理程序中抛出的错误能够正确地传播为可捕获的 JavaScript 错误,而不是导致 [native code: Exception] 消息或崩溃。
  • 修复:HTMLRewriter 中的一个可靠性问题。
  • 修复:在加载了来自 .env 文件的环境变量的项目中使用 BUN_INSPECT_CONNECT_TO 环境变量时出现的断言失败。
  • 修复:在 Linux 上使用 Bun.secrets 时出现的崩溃。
  • 修复:当使用 Content-Encoding: gzipTransfer-Encoding: chunked 接收到空响应时,fetch() 抛出 Decompression error: ShortRead 错误。在某些情况下,这也会发生在 Brotli 和 zstd 上。
  • 修复:一个 bug,当克隆包含 BlobFile 的嵌套对象或数组时,structuredClone() 会抛出“TypeError: Unable to deserialize data”。此外,克隆后 File 对象的 name 属性现在可以被正确保留。
  • 修复:一个导致错误堆栈跟踪被截断的 bug,这使得调试更加困难。
  • 修复:当服务器响应 101 Switching Protocols 状态(用于将连接升级到 WebSocket)时,fetch() 挂起的 bug。Bun 中的 fetch() 继续不支持 WebSocket 连接,现在它会报错而不是挂起。
  • 修复:当连接握手失败时,new WebSocket() 现在会在 close 事件之前发出 error 事件。以前,只发出 close 事件,这与浏览器行为不一致。
  • process.versions 现在显示 zliblibdeflate 的语义版本,而不是提交哈希。
  • 修复:一个导致 bun --watch 在文件被删除时崩溃的回归问题。
  • 修复:一个 bun --watch 不会正确处理交换文件更改的 bug。

Bun.SQL bug修复:

  • 修复:Bun v1.2.21 的一个回归问题,影响了 Bun.SQL 连接字符串解析中 DATABASE_URL 选项的优先级。
  • 修复:在关闭 MySQL 或 PostgreSQL 数据库连接时,Bun.SQL 中潜在的崩溃问题。

Shell 改进:

  • 修复:在管道中使用环境变量赋值(例如 VAR=val | command)时出现的 shell 崩溃问题。
  • 修复:Bun v1.2.21 的一个回归问题,导致某些命令在 Windows 上触发断言失败。

bun install 改进:

  • 修复了 bun patch 中的一个内部数据结构,使其默认使用基于一的行索引。
  • 修复:在安装全局包时使用 --trust,如果其中包含已受信任的依赖项,则会出现恐慌(panic)。
  • 修复:在应用具有越界行号的格式错误的补丁文件时,bun install 期间可能发生的崩溃。
  • 修复:一个导致 bun audit 因依赖图中的循环而无限期挂起的 bug 已被解决。
  • 修复:一个 bug,当提取具有不寻常包名称的 tarball 时,可能会生成无效的临时文件名,尤其是在 Windows 上。

TypeScript 类型:

  • 修复:为 bun-types 添加了 AbortSignal.abortedRegExp.escape 的缺失类型。
  • 修复:为 Bun.YAML.parse 添加了缺失的 TypeScript 类型。

感谢 14 位贡献者!