Rush Stack商店博客活动
跳至主要内容

Rush 子空间

什么是子空间?

子空间是 Rush 的一项功能,它使单个单体仓库能够使用多个 PNPM 锁文件进行安装。例如,如果子空间名称为 my-team,则将有一个文件夹 common/config/subspaces/my-team/,其中包含 pnpm-lock.yaml 文件和相关配置。每个 Rush 项目都属于一个子空间,并且单体仓库仍然有一个统一的“工作区”。因此,项目的 package.json 文件可以使用 workspace: 说明符来依赖来自其他子空间的项目。

好处是什么?

通常最好为整个单体仓库使用一个锁文件,因为这可以优化安装时间并最大限度地减少管理版本冲突的维护工作。但是,在某些情况下,多个锁文件具有优势

  • 非常大的代码库: 锁文件可以看作是巨大的多变量方程,我们通过协调跨多个项目的 NPM 包版本选择来解决这些方程,以消除冲突并最大限度地减少重复。(Lockfile Explorer 文档对此进行了深入说明。)将单体仓库依赖项划分为较小的锁文件确实使这些方程变得更小且更容易解决,但代价是增加了管理版本的总开销。对于非常庞大的工程团队,划分工作比最小化工作总量更重要。

  • 解耦项目集: 庞大的代码库可能有一些项目集群,其依赖项与仓库的其余部分不一致。例如,假设 50 个项目构成一个使用已弃用或过时框架的遗留应用程序,并且没有业务动机对其进行现代化。将这些项目移入子空间使它们的版本控制可以独立管理。

  • 安装测试: 发布 NPM 包时,某些错误无法使用 workspace:* 符号链接进行复制。例如,幽灵依赖项或不正确的 .npmignore glob 将导致包的外部使用者出现故障,但在单体仓库内测试相同的库时可能会正常工作。将测试项目移入子空间(结合 注入的依赖项)会产生更准确的安装,从而可以捕获此类问题,同时避免实际发布到测试 NPM 仓库的开销。

我需要多少个子空间?

我们通常建议“尽可能少”以最大限度地减少额外的版本管理开销。每个团队一个子空间 是一个合理的最高限制。也就是说,此功能已在具有超过 1,000 个子空间的生产单体仓库中成功使用。

现实世界演示

Rush Stack 自己的 GitHub 仓库当前配置了两个子空间

功能设计

每个子空间必须在其名称在 common/config/subspaces.json 配置文件中集中注册。使用 rush.json 中的 subspaceName 字段将项目添加到子空间。

每个子空间的配置都放在一个文件夹 common/config/subspaces/<subspace-name>/ 中,该文件夹可能包含以下文件

文件目的
common-versions.jsonRush 版本覆盖
pnpm-config.jsonPNPM 版本覆盖
pnpm-lock.yamlPNPM 锁文件
repo-state.jsonRush 生成的配置文件,用于防止手动更改锁文件
.npmrc包管理器配置
.pnpmfile-subspace.cjs程序版本覆盖,遵循与 .pnpmfile.cjs 相同的规范,但特定于子空间

某些文件可以在全局范围内配置(应用于整个单体仓库),除了子空间级别

子空间配置文件全局配置文件继承
common-versions.json启用子空间后,禁止使用全局文件
pnpm-config.jsoncommon/config/rush/pnpm-config.json(仍在开发中) 子空间优先,但会忽略某些字段
pnpm-lock.yaml启用子空间后,禁止使用全局文件
repo-state.json启用子空间后,禁止使用全局文件
.npmrccommon/config/rush/.npmrc子空间覆盖优先
.pnpmfile-subspace.cjscommon/config/rush/.pnpmfile.cjs子空间覆盖优先

请注意,以下配置文件不会移动

  • common/config/.npmrc-publish:此文件用于 Rush NPM 发布,无论已发布的项目属于哪个子空间。
  • common/config/.pnpmfile.cjs:此文件可以应用影响单体仓库中所有子空间的版本控制覆盖。为了避免在锁文件之间产生混乱的交互,在大多数情况下,最好使用 .pnpmfile-subspace.cjs 代替。

如果没有子空间,Rush 会在 common/temp/ 文件夹中生成和安装 PNPM 工作区。如果启用了子空间,这将在例如 common/temp/<subspace-name>/ 的文件夹中分别执行。

有两种基本的操作模式

  1. 只有几个子空间: 可以在 subspaces.json 中设置 "preventSelectingAllSubspaces": false,并且默认情况下,rush install 将安装所有子空间。

  2. 大量的子空间: 如果安装所有子空间会占用太多时间和磁盘空间,则可以设置 "preventSelectingAllSubspaces": true。在这种模式下,在调用 rush installrush update 等命令时,用户必须以某种方式过滤子空间,例如

    • rush install --to my-project 仅安装给定项目的依赖项
    • rush install --subspace my-subspace 仅安装特定子空间
    • rush install --to subspace:my-subspace 使用 项目选择器 来安装属于给定子空间的项目

如何启用子空间

  1. 确保你的 rush.json 指定了 "rushVersion": "5.122.0" 或更高版本,以及 "pnpmVersion": "8.7.6" 或更高版本。

  2. 使用 subspaces.json 来启用该功能并定义子空间。可以从 subspaces.json 文档中复制此文件的模板,或者使用 rush init 生成它。在本教程中,我们将创建一个名为 install-test 的子空间,用于测试 NPM 包

    common/config/rush/subspaces.json

    {
    "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/subspaces.schema.json",

    /**
    * Set this flag to "true" to enable usage of subspaces.
    */
    "subspacesEnabled": false,

    /**
    * When a command such as "rush update" is invoked without the "--subspace" or "--to"
    * parameters, Rush will install all subspaces. In a huge monorepo with numerous subspaces,
    * this would be extremely slow. Set "preventSelectingAllSubspaces" to true to avoid this
    * mistake by always requiring selection parameters for commands such as "rush update".
    */
    "preventSelectingAllSubspaces": false,

    /**
    * The list of subspace names, which should be lowercase alphanumeric words separated by
    * hyphens, for example "my-subspace". The corresponding config files will have paths
    * such as "common/config/subspaces/my-subspace/package-lock.yaml".
    */
    "subspaceNames": [
    // The "default" subspace always exists even if you don't define it,
    // but let's include it for clarity
    "default",

    "install-test" // 👈👈👈 Our secondary subspace name
    ]
    }
  3. 创建 default 子空间文件夹并将现有配置文件移动到那里

    cd my-repo
    mkdir --parents common/config/subspaces/default

    # Move these files:
    mv common/config/rush/common-versions.json common/config/subspaces/default/
    mv common/config/rush/pnpm-lock.yaml common/config/subspaces/default/
    mv common/config/rush/.npmrc common/config/subspaces/default/

    # Rename this file:
    mv common/config/rush/.pnpmfile.cjs common/config/subspaces/default/.pnpmfile-subspace.cjs
  4. 创建 install-test 子空间文件夹

    cd my-repo
    mkdir --parents common/config/subspaces/install-test
  5. 通过编辑 rush.json 将项目分配给子空间。例如

    rush.json

    . . .

    "projects": [
    {
    "packageName": "my-library-test",
    "projectFolder": "test-projects/my-library-test",
    "subspaceName": "install-test"
    }

    . . .

    如果省略了任何项目的 "subspaceName",它们将属于 default 子空间。

  6. 现在更新新子空间的锁文件

    # Clean out the common/temp folder from before
    rush purge

    # Regenerate the "default" subspace:
    rush update --full --subspace default

    # Regenerate the "install-test" subspace:
    rush update --full --subspace install-test

    注意: 你可以在不使用 --full 来重新生成任何锁文件的情况下迁移到子空间,但这将是一个更复杂的过程,可能需要使用脚本来重写 pnpm-lock.yaml 文件中的某些路径。

另请参阅