与 Rush 集成
The Hello World tutorial showed how Heft can be used in a standalone project. Now let's look at how Heft works in the context of a Rush monorepo.
How Heft gets invoked
If you're new to Rush, the maintainer tutorials explain the basics of setting up a new repo. Heft takes over when Rush invokes the "build"
script in a Rush project folder. In our sample project from the tutorial, the script looked like this
<项目文件夹>/package.json
{
. . .
"scripts": {
"build": "heft build --clean",
"start": "node lib/start.js"
}
. . .
}
Sharing configuration using rig packages
在 monorepo 中,一个主要主题是最小化“样板文件”。换句话说,合并原本需要复制粘贴到 monorepo 中每个项目文件夹的文件和设置。样板文件很麻烦,因为很难保持同步。当需要修复时,如果拥有数百个项目,则需要对数百个项目进行相同的修复。(更糟糕的是,如果工程师被允许以不同的方式自定义他们的项目,则可能需要进行数百种不同的修复,这将带来非常高的维护成本。)
同时,我们希望遵循 Rush 的项目隔离原则:每个项目都应独立构建,不应与其他项目纠缠在一起(例如,通过使用类似 ../../other-project
的相对路径引用文件)。这种纪律促进了 Rush 功能,例如子集构建和增量构建。它还使 Rush 项目文件夹的移动变得非常容易,能够将项目迁移到不同的 monorepo 之间,甚至在改变主意后不再使用 Rush。出于这个原因,我们不鼓励将集中式 .eslintrc.js 文件放在 monorepo 的根目录中并全局调用 ESLint 来检查所有项目的做法。
结合这些目标,Heft 支持一种名为 rig 包 的形式,其中常见设置由添加到每个项目 devDependencies
中的 NPM 包提供。rig 包提供了三种不同的方法来减少重复
- 配置文件可以使用
"extends"
等设置从 rig 继承常见设置。示例:tsconfig.json - 可配置的配置文件可以通过 config/rig.json 文件完全消除,该文件指示 Heft 在 rig 包中查找它们。示例:config/heft.json
- 可配置的依赖项可以由 rig 包提供,避免需要将它们添加到项目的
devDependencies
中。示例:typescript 包
The Using rig packages article describes this in detail.
增量构建
使用 Rush 与 Heft 的另一个好处是支持增量构建。例如,如果两次运行 rush build
,第二次将立即完成,因为所有项目都已经构建完成。有趣的是,这种增量构建分析由 Rush 本身执行,而不是 Heft。
由于 JavaScript 是一种解释性语言,因此每次在项目文件夹中启动 Node.js 进程时都会产生少量开销。因此,即使 Heft 完全没有执行任何操作,也可能需要 1 秒钟才能启动工具链、分析输入文件并确定所有内容都已更新。对于拥有 500 个项目的 monorepo,这将累计分析 500 秒。Rush 通过对所有项目的全局分析来避免这种情况,比较源文件的哈希值与输出文件的哈希值。如果这些哈希值相同,那么 Rush 可以确定可以完全跳过该项目,甚至无需启动 Heft。Rush 的增量构建分析适用于任何行为良好的脚本,而不仅仅是 Heft。
使用 Heft 阶段实现 Rush 阶段
可以使用 Rush 阶段 使 Rush 的增量构建更加细粒度。Heft 阶段专门设计用于与这种模型保持一致。
这是 GitHub 上 Rush Stack monorepo 中 node-core-library/package.json 的摘录
"scripts": {
"build": "heft build --clean",
"test": "heft test --clean",
"_phase:build": "heft run --only build -- --clean",
"_phase:test": "heft run --only test -- --clean"
},
"test"
命令调用 heft test
,它将执行 build
和 test
阶段,而 "_phase:test"
命令只执行 test
阶段。这是因为 config/rush/command-line.json 对我们的阶段依赖项进行了建模,因此 Rush 本身将确保在执行 test
之前运行 build
阶段。通过将这些细节公开给 Rush,Heft 的阶段可以使用 Rush 的构建缓存进行优化,甚至可以通过 Cobuild 功能参与分布式构建。