[博客翻译]Bun 1.2发布


原文地址:https://bun.sh/blog/bun-v1.2


Bun 1.2 发布

Bun 是一个用于构建和测试全栈 JavaScript 和 TypeScript 应用的完整工具包。如果你还不熟悉 Bun,可以通过 Bun 1.0 的博客文章了解更多。

Bun 1.2 更新亮点

Bun 1.2 是一个重大更新,我们非常兴奋地与大家分享。以下是 Bun 1.2 的主要变化:

  • Node.js 兼容性:Bun 在 Node.js 兼容性方面取得了重大进展。
  • 内置 S3 对象存储 API:新增了 Bun.s3,支持与 S3 存储的交互。
  • 内置 Postgres 客户端:新增了 Bun.sql,支持 Postgres 数据库操作(MySQL 支持即将推出)。
  • bun install 使用基于文本的锁文件bun.lock 取代了之前的二进制锁文件。

此外,Bun 1.2 还让 Express 框架的性能提升了 3 倍。

Node.js 兼容性

Bun 旨在成为 Node.js 的直接替代品。在 Bun 1.2 中,我们开始为每次 Bun 的更改运行 Node.js 测试套件。自那时起,我们已经修复了数千个错误,以下 Node.js 模块在 Bun 中的测试通过率超过了 90%。

如何衡量兼容性?

在 Bun 1.2 中,我们改变了测试和改进 Bun 与 Node.js 兼容性的方式。以前,我们根据用户报告的 GitHub 问题来优先修复 Node.js 的 bug。虽然这解决了用户遇到的实际问题,但这种方式过于被动,难以实现 100% 的 Node.js 兼容性。

于是我们想到:为什么不直接运行 Node.js 的测试套件呢?

在 Bun 中运行 Node.js 测试

Node.js 的测试套件包含数千个测试文件,大部分位于 test/parallel 目录中。虽然“直接运行”这些测试听起来很简单,但实际上比想象中复杂得多。

内部 API

许多测试依赖于 Node.js 的内部实现细节。例如,以下测试中,getnameinfo 被模拟为总是出错,以测试 dns.lookupService() 的错误处理。

const { internalBinding } = require("internal/test/binding");
const cares = internalBinding("cares_wrap");
const { UV_ENOENT } = internalBinding("uv");
cares.getnameinfo = () => UV_ENOENT;

为了在 Bun 中运行这个测试,我们不得不用自己的模拟替换内部绑定。

Bun.dns.lookupService = (addr, port) => {
  const error = new Error(`getnameinfo ENOENT ${addr}`);
  error.code = "ENOENT";
  error.syscall = "getnameinfo";
  throw error;
};

错误信息

还有一些 Node.js 测试会检查错误信息的精确字符串。虽然 Node.js 通常不会更改错误信息,但它们并不保证在版本之间不会发生变化。

const common = require("../common");
const assert = require("assert");
const cp = require("child_process");
assert.throws(
  () => {
    cp.spawnSync(process.execPath, [__filename, "child"], { argv0: [] });
  },
  {
    code: "ERR_INVALID_ARG_TYPE",
    name: "TypeError",
    message: 'The "options.argv0" property must be of type string.' + common.invalidArgTypeHelper([]),
  }
);

为了解决这个问题,我们不得不修改一些测试的断言逻辑,改为检查 namecode,而不是 message

{
  code: "ERR_INVALID_ARG_TYPE",
  name: "TypeError",
  message: 'The "options.argv0" property must be of type string.' + common.invalidArgTypeHelper([]),
}

虽然我们尽量匹配 Node.js 的错误信息,但有时我们也会提供更有帮助的错误信息,只要 namecode 相同即可。

目前的进展

我们已经将数千个 Node.js 测试文件移植到 Bun 中。这意味着每次我们对 Bun 进行更改时,都会运行 Node.js 测试套件以确保兼容性。

每天,我们都在为 Bun 添加越来越多的 Node.js 测试通过率,我们很快会分享更多关于 Node.js 兼容性的进展。

除了修复现有的 Node.js API,我们还添加了对以下 Node.js 模块的支持。

node:http2 服务器

你现在可以使用 node:http2 来创建 HTTP/2 服务器。HTTP/2 也是 gRPC 服务器的必要条件,Bun 现在也支持 gRPC 服务器。之前,Bun 只支持 HTTP/2 客户端。

import { createSecureServer } from "node:http2";
import { readFileSync } from "node:fs";
const server = createSecureServer({
  key: readFileSync("key.pem"),
  cert: readFileSync("cert.pem"),
});
server.on("stream", (stream, headers) => {
  stream.respond({
    ":status": 200,
    "content-type": "text/html; charset=utf-8",
  });
  stream.end("<h1>Hello from Bun!</h1>");
});
server.listen(3000);

在 Bun 1.2 中,HTTP/2 服务器的性能比 Node.js 快 2 倍。当我们为 Bun 添加新 API 时,我们会花很多时间优化性能,确保它不仅能用,而且更快。

node:dgram

你现在可以使用 node:dgram 绑定和连接到 UDP 套接字。UDP 是一种低级别的不可靠消息协议,通常用于遥测提供商和游戏引擎。

import { createSocket } from "node:dgram";
const server = createSocket("udp4");
const client = createSocket("udp4");
server.on("listening", () => {
  const { port, address } = server.address();
  for (let i = 0; i < 10; i++) {
    client.send(`data ${i}`, port, address);
  }
  server.unref();
});
server.on("message", (data, { address, port }) => {
  console.log(`Received: data=${data} source=${address}:${port}`);
  client.unref();
});
server.bind();

这使得像 DataDog 的 dd-trace@clickhouse/client 这样的包可以在 Bun 1.2 中正常工作。

node:cluster

你可以使用 node:cluster 来生成多个 Bun 实例。这通常用于通过跨多个 CPU 核心运行任务来提高吞吐量。

以下是一个使用 cluster 创建多线程 HTTP 服务器的示例:

  • 主工作进程生成 n 个子工作进程(通常等于 CPU 核心数)。
  • 每个子工作进程监听相同的端口(使用 reusePort)。
  • 传入的 HTTP 请求在子工作进程之间进行负载均衡。
import cluster from "node:cluster";
import { createServer } from "node:http";
import { cpus } from "node:os";
if (cluster.isPrimary) {
  console.log(`Primary ${process.pid} is running`);
  // 启动与 CPU 数量相等的工作进程
  for (let i = 0; i < cpus().length; i++) {
    cluster.fork();
  }
  cluster.on("exit", (worker, code, signal) => {
    console.log(`Worker ${worker.process.pid} exited`);
  });
} else {
  // 传入的请求由工作进程池处理,而不是主工作进程
  createServer((req, res) => {
    res.writeHead(200);
    res.end(`Hello from worker ${process.pid}`);
  }).listen(3000);
  console.log(`Worker ${process.pid} started`);
}

注意,reusePort 仅在 Linux 上有效。在 Windows 和 macOS 上,操作系统不会像预期的那样对 HTTP 连接进行负载均衡。

node:zlib

在 Bun 1.2 中,我们重写了整个 node:zlib 模块,从 JavaScript 改为原生代码。这不仅修复了许多 bug,还使其性能比 Bun 1.1 快 2 倍。

我们还为 node:zlib 添加了对 Brotli 的支持,这在 Bun 1.1 中是缺失的。

import { brotliCompressSync, brotliDecompressSync } from "node:zlib";
const compressed = brotliCompressSync("Hello, world!");
compressed.toString("hex"); // "0b068048656c6c6f2c20776f726c642103"
const decompressed = brotliDecompressSync(compressed);
decompressed.toString("utf8"); // "Hello, world!"

使用 V8 API 的 C++ 插件

如果你想在 JavaScript 代码中使用 C++ 插件,最简单的方法是使用 N-API

然而,在 N-API 出现之前,一些包使用了 Node.js 内部的 V8 C++ API。这使得事情变得复杂,因为 Node.js 和 Bun 使用不同的 JavaScript 引擎:Node.js 使用 V8(Chrome 使用的引擎),而 Bun 使用 JavaScriptCore(Safari 使用的引擎)。

以前,像 cpu-features 这样依赖这些 V8 API 的 npm 包在 Bun 中无法工作。

require("cpu-features")();
dyld[94465]: missing symbol called
fish: Job 1, 'bun index.ts' terminated by signal SIGABRT (Abort)

为了解决这个问题,我们进行了前所未有的工程努力,在 JavaScriptCore 中实现了 V8 的公共 C++ API,使得这些包可以在 Bun 中“直接运行”。这个实现非常复杂,我们甚至写了一篇 三部分的博客 来解释我们是如何在不使用 V8 的情况下支持 V8 API 的。

在 Bun 1.2 中,像 cpu-features 这样的包可以直接导入并运行。

$ bun index.ts
{
  arch: "aarch64",
  flags: {
    fp: true,
    asimd: true,
    // ...
  },
}

V8 C++ API 的支持非常复杂,因此大多数包仍然会有一些缺失的功能。我们将继续改进支持,以便像 node-canvas@v2node-sqlite3 这样的包在未来能够正常工作。

node:v8

除了 V8 C++ API,我们还添加了对使用 node:v8 进行堆快照的支持。

import { writeHeapSnapshot } from "node:v8";
// 将堆快照写入当前工作目录,文件名为 `Heap-{date}-{pid}.heapsnapshot`
writeHeapSnapshot();

在 Bun 1.2 中,你可以使用 getHeapSnapshotwriteHeapSnapshot 来读取和写入 V8 堆快照。这使得你可以使用 Chrome DevTools 来检查 Bun 的堆。

Express 性能提升 3 倍

虽然兼容性对于修复 bug 很重要,但它也帮助我们修复了 Bun 中的性能问题。

在 Bun 1.2 中,流行的 express 框架处理 HTTP 请求的速度比 Node.js 快 3 倍。这是通过改进与 node:http 的兼容性以及优化 Bun 的 HTTP 服务器实现的。

S3 支持与 Bun.s3

Bun 旨在成为一个面向云的 JavaScript 运行时。这意味着它支持你在云中运行生产应用所需的所有工具和服务。

现代应用通常将文件存储在对象存储中,而不是本地的 POSIX 文件系统。当终端用户将文件附件上传到网站时,文件不会存储在服务器的本地磁盘上,而是存储在 S3 存储桶中。将存储与计算解耦可以避免一系列可靠性问题:磁盘空间不足、繁忙的 I/O 导致的高 p95 响应时间,以及共享文件存储的安全问题。

S3 是云中对象存储的事实标准。S3 API 由多种云服务实现,包括 Amazon S3、Google Cloud Storage、Cloudflare R2 等。

这就是为什么 Bun 1.2 添加了对 S3 的内置支持。你可以使用与 Web 标准兼容的 API(如 Blob)从 S3 存储桶中读取、写入和删除文件。

从 S3 读取文件

你可以使用新的 Bun.s3 API 来访问默认的 S3Client。客户端提供了一个 file() 方法,返回对 S3 文件的懒引用,这与 Bun 的 File API 相同。

import { s3 } from "bun";
const file = s3.file("folder/my-file.txt");
// file instanceof Blob
const content = await file.text();
// 或者:
//  file.json()
//  file.arrayBuffer()
//  file.stream()

比 Node.js 快 5 倍

Bun 的 S3 客户端是用原生代码编写的,而不是 JavaScript。与使用 @aws-sdk/client-s3 的 Node.js 相比,Bun 从 S3 存储桶下载文件的速度快 5 倍。

将文件写入 S3

你可以使用 write() 方法将文件上传到 S3。非常简单:

import { s3 } from "bun";
const file = s3.file("folder/my-file.txt");
await file.write("hello s3!");
// 或者:
//  file.write(new Uint8Array([1, 2, 3]));
//  file.write(new Blob(["hello s3!"]));
//  file.write(new Response("hello s3!"));

对于较大的文件,你可以使用 writer() 方法获取一个文件写入器,进行多部分上传,这样你就不必担心细节。

import { s3 } from "bun";
const file = s3.file("folder/my-file.txt");
const writer = file.writer();
for (let i = 0; i < 1000; i++) {
  writer.write(String(i).repeat(1024));
}
await writer.end();

预签名 URL

当你的生产服务需要让用户上传文件到服务器时,通常更可靠的做法是让用户直接上传到 S3,而不是通过服务器作为中介。

为了实现这一点,你可以使用 presign() 方法生成文件的预签名 URL。这会生成一个带有签名的 URL,允许用户安全地上传特定文件到 S3,而不会暴露你的凭证或授予他们不必要的访问权限。

import { s3 } from "bun";
const url = s3.presign("folder/my-file.txt", {
  expiresIn: 3600, // 1 小时
  acl: "public-read",
});

使用 Bun.serve()

由于 Bun 的 S3 API 扩展了 File API,你可以使用 Bun.serve() 通过 HTTP 提供 S3 文件。

import { serve, s3 } from "bun";
serve({
  port: 3000,
  async fetch(request) {
    const { url } = request;
    const { pathname } = new URL(url);
    // ...
    if (pathname === "/favicon.ico") {
      const file = s3.file("assets/favicon.ico");
      return new Response(file);
    }
    // ...
  },
});

当你使用 new Response(s3.file(...)) 时,Bun 不会将 S3 文件下载到服务器并发送给用户,而是将用户重定向到 S3 文件的预签名 URL。

Response (0 KB) {
  status: 302,
  headers: Headers {
    "location": "https://s3.amazonaws.com/my-bucket/assets/favicon.ico?...",
  },
  redirected: true,
}

这节省了内存、时间和下载文件到服务器的带宽成本。

使用 Bun.file()

如果你想使用与本地文件系统相同的代码访问 S3 文件,可以使用 s3:// URL 协议引用它们。这与使用 file:// 引用本地文件的概念相同。

import { file } from "bun";
async function createFile(url, content) {
  const fileObject = file(url);
  if (await fileObject.exists()) {
    return;
  }
  await fileObject.write(content);
}
await createFile("s3://folder/my-file.txt", "hello s3!");
await createFile("file://folder/my-file.txt", "hello posix!");

使用 fetch()

你甚至可以使用 fetch() 从 S3 读取、写入和删除文件。

// 上传到 S3
await fetch("s3://folder/my-file.txt", {
  method: "PUT",
  body: "hello s3!",
});
// 从 S3 下载
const response = await fetch("s3://folder/my-file.txt");
const content = await response.text(); // "hello s3!"
// 从 S3 删除
await fetch("s3://folder/my-file.txt", {
  method: "DELETE",
});

使用 S3Client

当你导入 Bun.s3 时,它会返回一个默认客户端,该客户端使用已知的环境变量(如 AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY)进行配置。

import { s3, S3Client } from "bun";
// s3 instanceof S3Client

你也可以创建自己的 S3Client,然后将其设置为默认客户端。

import { S3Client } from "bun";
const client = new S3Client({
  accessKeyId: "my-access-key-id",
  secretAccessKey: "my-secret-access-key",
  region: "auto",
  endpoint: "https://<account-id>.r2.cloudflarestorage.com",
  bucket: "my-bucket",
});
// 将默认客户端设置为你的自定义客户端
Bun.s3 = client;

Postgres 支持与 Bun.sql

与对象存储一样,生产应用通常需要的另一个数据存储是 SQL 数据库。

从一开始,Bun 就内置了 SQLite 客户端。SQLite 非常适合小型应用和快速脚本,你不需要担心设置生产数据库的麻烦。

在 Bun 1.2 中,我们通过引入 Bun.sql 扩展了 Bun 对 SQL 数据库的支持,这是一个内置的 SQL 客户端,支持 Postgres。我们还有一个 pull request 即将添加 MySQL 支持。

使用 Bun.sql

你可以使用 Bun.sql 通过标签模板字面量运行 SQL 查询。这允许你将 JavaScript 值作为参数传递给 SQL 查询。

最重要的是,它会自动转义字符串并使用预处理语句,以防止 SQL 注入。

import { sql } from "bun";
const users = [
  { name: "Alice", age: 25 },
  { name: "Bob", age: 65 },
];
await sql`
  INSERT INTO users (name, age)
  VALUES ${sql(users)}
`;

读取行同样简单。结果以对象数组的形式返回,键为列名。

import { sql } from "bun";
const seniorAge = 65;
const seniorUsers = await sql`
  SELECT name, age FROM users
  WHERE age >= ${seniorAge}
`;
console.log(seniorUsers); // [{ name: "Bob", age: 65 }]

比其他客户端快 50%

Bun.sql 是用原生代码编写的,具有以下优化:

  • 自动预处理语句
  • 查询流水线
  • 二进制协议支持
  • 连接池
  • 结构缓存

这些优化就像《魔兽世界》中的增益效果一样叠加在一起。结果是,Bun.sql 在读取行时比使用 Node.js 中最流行的 Postgres 客户端快 50%。

postgres.js 迁移到 Bun.sql

Bun.sql 的 API 灵感来自于流行的 postgres.js 包。这使得你可以轻松地将现有代码迁移到使用 Bun 的内置 SQL 客户端。

import { postgres } from "postgres";
import { postgres } from "bun";
const sql = postgres({
  host: "localhost",
  port: 5432,
  database: "mydb",
  user: "...",
  password: "...",
});
const users = await sql`SELECT name, age FROM users LIMIT 1`;
console.log(users); // [{ name: "Alice", age: 25 }]

Bun 是一个包管理器

Bun 是一个与 npm 兼容的包管理器,可以轻松安装和更新你的 node 模块。你可以使用 bun install 来安装依赖项,即使你使用的是 Node.js 作为运行时。

bun install 替换 npm install

$ npm install
$ bun install

在 Bun 1.2 中,我们对包管理器进行了最大的更改。

bun.lockb 的问题

从一开始,Bun 就使用了二进制锁文件:bun.lockb

与其他使用基于文本的锁文件(如 JSON 或 YAML)的包管理器不同,二进制锁文件使得 bun installnpm 快近 30 倍。

然而,我们发现使用二进制锁文件有很多小问题。首先,你无法在 GitHub 和其他平台上查看锁文件的内容。这很糟糕。

如果你收到一个外部贡献者的拉取请求,更改了 bun.lockb 文件,你会信任它吗?可能不会。

这也使得工具难以读取锁文件。例如,像 Dependabot 这样的依赖管理工具需要一个 API 来解析锁文件,而我们没有提供。

Bun 将继续支持 bun.lockb 很长时间。然而,出于这些原因,我们决定在 Bun 1.2 中切换到基于文本的锁文件作为默认选项。

引入 bun.lock

在 Bun 1.2 中,我们引入了一个新的基于文本的锁文件:bun.lock

你可以使用 --save-text-lockfile 标志迁移到新的锁文件。

bun install --save-text-lockfile

bun.lock 是一个 JSONC 文件,支持注释和尾随逗号。

// bun.lock
{
  "lockfileVersion": 0,
  "packages": [
    ["express@4.21.2", /* ... */, "sha512-..."],
    ["body-parser@1.20.3", /* ... */],
    /* ... and more */
  ],
  "workspaces": { /* ... */ },
}

这使得在拉取请求中查看差异变得更加容易,尾随逗号也减少了合并冲突的可能性。

对于没有锁文件的新项目,Bun 将生成一个新的 bun.lock 文件。

对于已有 bun.lockb 文件的项目,Bun 将继续支持二进制锁文件,无需迁移到新的锁文件。我们将继续支持二进制锁文件很长时间,因此你可以继续使用像 bun addbun update 这样的命令,它们将更新你的 bun.lockb 文件。

bun install 速度提升 30%

你可能会认为,在我们迁移到基于文本的锁文件后,bun install 会变慢。错了!

大多数软件项目随着功能的增加而变慢,但 Bun 不是这样的项目。我们花了很多时间调整和优化 Bun,使得 bun install 甚至更快。

这就是为什么在 Bun 1.2 中,bun install 比 Bun 1.1 快 30%。

package.json 支持 JSONC

你是否曾经在 package.json 中添加了某些内容,几个月后却忘记了为什么?或者想向你的团队成员解释为什么某个依赖需要特定版本?或者因为逗号导致 package.json 文件出现合并冲突?

通常这些问题是因为 package.json 是一个 JSON 文件,这意味着你不能在其中使用注释或尾随逗号。

{
  "dependencies": {
    // 这会导致语法错误
    "express": "4.21.2"
  }
}

这是一个糟糕的体验。现代工具如 TypeScript 允许在它们的配置文件中使用注释和尾随逗号,例如 tsconfig.json,这很棒。我们还询问了社区的意见,似乎现状需要改变。

在 Bun 1.2 中,你可以在 package.json 中使用注释和尾随逗号。它直接生效。

{
  "name": "app",
  "dependencies": {
    // 我们需要 0.30.8,因为 0.30.9 有一个 bug
    "drizzle-orm": "0.30.8", /* <- 尾随逗号 */
  },
}

由于有许多工具读取 package.json 文件,我们添加了对 require()import() 这些带有注释和尾随逗号的文件的支持。你不需要更改代码。

const pkg = require("./package.json");
const {
  default: { name },
} = await import("./package.json");

由于这在 JavaScript 生态系统中并不广泛支持,我们建议你“自担风险”使用此功能。然而,我们认为这是正确的方向:让事情对你来说更容易。

.npmrc 支持

在 Bun 1.2 中,我们添加了对读取 npm 配置文件 .npmrc 的支持。

你可以使用 .npmrc 来配置 npm 注册表和范围包。这在企业环境中通常是必要的,因为你可能需要认证到私有注册表。

@my-company:registry=https://packages.my-company.com
@my-org:registry=https://packages.my-company.com/my-org

Bun 会在项目的根目录和你的主目录中查找 .npmrc 文件。

bun run --filter

你现在可以使用 bun run --filter 同时在多个工作区中运行脚本。

bun run --filter='*' dev

这将在所有匹配通配符模式的工作区中并发运行 dev 脚本。它还会交错每个脚本的输出,因此你可以看到每个工作区的输出。

你也可以传递多个过滤器给 --filter,并且你可以直接使用 bun 而不是 bun run

bun --filter 'api/*' --filter 'frontend/*' dev

bun outdated

你现在可以使用 bun outdated 查看哪些依赖项已过时。

它会显示你的 package.json 依赖项列表,以及哪些版本已过时。“更新”列显示下一个符合 semver 的版本,“最新”列显示最新版本。

如果你注意到有特定的依赖项需要更新,可以使用 bun update

bun update @typescript-eslint/parser # 更新到 "7.18.0"
bun update @typescript-eslint/parser --latest # 更新到 "8.2.0"

你也可以过滤你想检查更新的依赖项。只需确保引用模式,以免你的 shell 将其扩展为通配符模式!

bun outdated "is-*" # 检查 is-even, is-odd 等
bun outdated "@discordjs/*" # 检查 @discordjs/voice, @discordjs/rest 等
bun outdated jquery --filter="foo" # 在 `foo` 工作区中检查 jquery

bun publish

你现在可以使用 bun publish 发布 npm 包。

它是 npm publish 的直接替代品,支持许多相同的功能,例如:

  • 读取 .npmrc 文件进行认证。
  • 打包 tarball,考虑多个目录中的 .gitignore.npmignore 文件。
  • OTP / 双因素认证。
  • 处理 package.json 字段的边缘情况,如 binfiles 等。
  • 小心处理缺失的 README 文件。

我们还添加了对发布有用的命令,例如:

  • bun pm whoami,打印你的 npm 用户名。
  • bun pm pack,创建一个 npm 包 tarball 以便发布或本地安装。

bun patch

有时,你的依赖项有 bug 或缺少功能。虽然你可以 fork 该包,进行更改并发布它,但这需要很多工作。如果你不想维护一个 fork 呢?

在 Bun 1.2 中,我们添加了对依赖项打补丁的支持。以下是它的工作原理:

  1. 运行 bun patch <package> 来打补丁。
  2. 编辑 node_modules/<package> 目录中的文件。
  3. 运行 bun patch --commit <package> 来保存你的更改。就这样!

Bun 会在 patches/ 目录中生成一个 .patch 文件,其中包含你的更改,该文件会在 bun install 时自动应用。然后你可以将补丁文件提交到你的仓库,并与你的团队分享。

例如,你可以创建一个补丁来用你自己的代码替换依赖项。

diff --git a/index.js b/index.js
index 832d92223a9ec491364ee10dcbe3ad495446ab80..2a61f0dd2f476a4a30631c570e6c8d2d148d419a 100644
--- a/index.js
+++ b/index.js
@@ -1,14 +1 @@
- 'use strict';
-
- var isOdd = require('is-odd');
-
- module.exports = function isEven(i) {
-  return !isOdd(i);
- };
+ module.exports = (i) => (i % 2 === 0)

Bun 从 node_modules 目录中克隆该包,并使用其自身的副本。这允许你安全地编辑包目录中的文件,而不会影响共享文件缓存。

更易用

我们还对 bun install 进行了许多小的改进,使其更易用。

CA 证书

你现在可以为 bun install 配置 CA 证书。这在需要从公司的私有注册表安装包或使用自签名证书时非常有用。

[install]
# CA 证书作为字符串
ca="-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
# CA 证书文件的路径。该文件可以包含多个证书。
cafile="path/to/cafile"

如果你不想更改 bunfig.toml 文件,你也可以使用 --ca--cafile 标志。

bun install --cafile=/path/to/cafile
bun install --ca="..."

如果你使用的是现有的 .npmrc 文件,你也可以在那里配置 CA 证书。

cafile=/path/to/cafile
ca="..."

bundleDependencies 支持

你现在可以在 package.json 中使用 bundleDependencies

{
  "bundleDependencies": ["is-even"]
}

这些是你期望已经存在于 node_modules 文件夹中的依赖项,它们不会像其他依赖项一样被安装。

bun add 尊重 package.json 缩进

我们修复了一个 bug,即 bun add 不会尊重 package.json 中的缩进。Bun 现在会保留 package.json 的缩进,无论它有多奇怪。

bun add is-odd
// 一个故意奇怪的 package.json
{
  "dependencies": {
    "is-even": "1.0.0",
    "is-odd": "1.0.0"
  }
}

--omit=dev|optional|peer 支持

Bun 现在支持 bun install--omit 标志,允许你省略开发、可选或对等依赖项。

bun install --omit=dev # 省略开发依赖项
bun install --omit=optional # 省略可选依赖项
bun install --omit=peer # 省略对等依赖项
bun install --omit=dev --omit=optional # 省略开发
阅读全文(20积分)