运行时包管理器打包器测试运行器代码检查格式化指南参考博客反馈

工作区

开发包含多个独立包的复杂多包仓库(monorepo)

Bun 支持在 package.json 中配置 workspaces。借助工作区,你可以在单个仓库中开发多个独立的包,这种仓库称为 monorepo。

多包仓库通常具有以下结构:

File
<root>
├── README.md
├── bun.lock
├── package.json
├── tsconfig.json
└── packages
    ├── pkg-a
    │   ├── index.ts
    │   ├── package.json
    │   └── tsconfig.json
    ├── pkg-b
    │   ├── index.ts
    │   ├── package.json
    │   └── tsconfig.json
    └── pkg-c
        ├── index.ts
        ├── package.json
        └── tsconfig.json

根目录 package.json 中的 "workspaces" 键列出了要作为工作区处理的子目录。按照惯例,这些目录位于名为 packages 的目录中。

package.json
{
  "name": "my-project",
  "version": "1.0.0",
  "workspaces": ["packages/*"],
  "devDependencies": {
    "example-package-in-monorepo": "workspace:*"
  }
}
package.json
{
  "name": "my-project",
  "version": "1.0.0",
  "workspaces": ["packages/**", "!packages/**/test/**", "!packages/**/template/**"]
}

每个工作区都有自己的 package.json。要引用多包仓库中的另一个包,请在 package.json 中将 semver 范围或工作区协议(例如 workspace:*)用作版本。

packages/pkg-a/package.json
{
  "name": "pkg-a",
  "version": "1.0.0",
  "dependencies": {
    "pkg-b": "workspace:*"
  }
}

bun install 会为多包仓库中的所有工作区安装依赖,并在可能的情况下对包进行去重。若只想为特定工作区安装依赖,请使用 --filter 标志。

bash
# 安装所有以 `pkg-` 开头且不包含 `pkg-c` 的工作区依赖
bun install --filter "pkg-*" --filter "!pkg-c"

# 也可以使用路径,这与上面命令效果相同。
bun install --filter "./packages/pkg-*" --filter "!pkg-c" # 或 --filter "!./packages/pkg-c"

发布时,Bun 会将 workspace: 版本替换为包的 package.json 版本:

Code
"workspace:*" -> "1.0.1"
"workspace:^" -> "^1.0.1"
"workspace:~" -> "~1.0.1"

指定的版本优先于包 package.json 中的版本:

Code
"workspace:1.0.2" -> "1.0.2" // 即使当前版本是 1.0.1

工作区有几个主要优点。

  • 将代码拆分为逻辑部分。 如果一个包依赖于另一个包,请在 package.json 中将其添加为依赖项。如果包 b 依赖于 a,bun install 会将本地 packages/a 目录安装到 node_modules,而不是从 npm 注册表下载它。
  • Bun 可以对依赖进行去重。 如果 a 和 b 共享一个依赖,Bun 会将它_提升_到根目录的 node_modules 目录。这可以节省磁盘空间,并尽可能避免同时安装同一个包的多个版本所导致的“依赖地狱”。
  • 在多个包中运行脚本。 使用 --filter 标志 一次在多个包中运行 package.json 脚本,或使用 --workspaces 在所有工作区中运行脚本。

自包含工作区

使用提升式链接器时,多个工作区共享的依赖会被提升到根目录的 node_modules。有些工具无法处理这种情况:Electron 打包器和无服务器打包器会遍历、精简并重新打包_单个工作区_的 node_modules,并期望每个依赖都实际存在于该目录下。可以在此类工作区的 package.json 中将其标记为自包含(使用 Yarn 所用的相同键;只有 "workspaces" 的值会改变布局):

apps/desktop/package.json
{
  "name": "desktop",
  "installConfig": { "hoistingLimits": "workspaces" }
}

也可以在根目录的 package.json 中,紧挨着工作区 glob 的位置进行配置:

package.json
{
  "workspaces": {
    "packages": ["apps/*", "packages/*"],
    "selfContained": ["apps/desktop"]
  }
}

(条目可以是工作区路径或包名称)

对于该工作区,bun install 会将其视为提升屏障——它直接或间接依赖的所有内容(包括通过它所依赖的其他工作区引入的内容)都不会被放置在 apps/desktop/node_modules 之上,因此该目录包含完整的依赖树;这些包会以实际副本的形式安装,而不是从缓存创建硬链接/克隆,因此重写这些包的工具不会影响缓存或其他项目。其他所有工作区仍会像往常一样将依赖提升到根目录。锁文件不会记录此设置。Bun 每次安装时都会从 package.json 中读取该设置,包括使用 --frozen-lockfile 时,因此无论是否启用此设置,锁文件都相同。此设置对隔离式链接器无效,因为在该模式下,每个包本来就只会解析自身的依赖。

使用 Catalogs 共享版本

当许多软件包需要使用相同的依赖版本时,请在根目录的 package.json 中的 catalog 里统一定义这些版本,然后在工作区中通过 catalog: 协议引用它们。更新 catalog 会同步更新所有引用它的软件包。请参阅 Catalogs。