使用监视模式
流行工具,如 Webpack 和 Jest 提供了“监视模式”功能:任务完成后,该工具进入一个循环,在其中监视文件系统以查看源文件的更改。每当检测到更改时,该任务都会再次运行以更新其输出。这加快了开发速度,因为 (1) 每当保存文件时,重建都会自动发生,以及 (2) 该任务可以从内存缓存中获益,因为其进程从未终止。
但这些功能通常只适用于单个项目。在使用单体仓库时,我们需要能够同时监视**多个项目**的监视模式。
思维实验
假设我们的单体仓库具有以下项目
在上图中,圆圈表示本地项目,而不是外部 NPM 依赖项。从 D
到 C
的箭头表示 D
依赖于 C
;这意味着必须先构建 C
,然后才能构建 D
。
假设您保存了对项目 B
的更改
对于多项目“监视模式”,我们希望按顺序发生以下事件
B
应该重建,因为其文件已更改;- 接下来,
C
应该重建,因为它依赖于B
- 接下来,
D
应该重建,因为它依赖于C
- 最后,Webpack 开发服务器(可能是
D
主持的)使用重建的应用程序刷新您的 Web 浏览器
如何使用 Rush 实现?假设我们的项目 B
和 C
有一个简单的构建脚本,如下所示
package.json
. . .
"scripts": {
"build": "rm -Rf lib/ && tsc && jest"
}
. . .
我们可以尝试一个实验,例如在无限循环中调用 rush build --to-except D
...
# Build everything that D depends on (but not D itself),
# and keep doing that in an endless loop:
while true; do rush build --to-except D; done
...然后,在运行此命令的同时,在项目 D
的文件夹中调用 heft start
(或 webpack serve
)。
您会发现这种方法存在一些问题
rm -Rf lib/
删除作为符号链接目标的文件。符号链接似乎会混淆 Webpack 的文件监视器,因此您可能会看到很多错误报告无法找到导入的文件。Webpack 无法从该错误中恢复,因为符号链接时间戳在文件稍后被重写时不会更新。jest
和rm -Rf
步骤通常在监视时无关紧要。开发人员的**编辑 -> 重建 -> 重新加载**的内部循环比它需要的时间长得多。
这些问题可以通过为监视模式创建特殊的简化脚本来解决,如下所示
package.json
. . .
"scripts": {
"build": "rm -Rf lib/ && tsc && jest",
"build:watch": "tsc"
}
. . .
“watchForChanges” 设置(实验性)
Rush 的多项目“监视模式”形式化了这个基本思想,使用优化的 chokidar 文件系统监视器替换了简单的循环。
启用 Rush 多项目监视模式的方式取决于您是使用批量命令还是分阶段命令作为构建脚本。我们建议在启用监视模式之前切换到分阶段构建,因为它对开发人员来说是一种更好、更易于理解的体验。
分阶段命令的监视模式
在 command-line.json 配置文件中,为要启用的每个分阶段命令添加新的
watchOptions
部分。例如. . .
"commands": [
{
"commandKind": "phased",
"name": "build",
"phases": ["_phase:build"],
"enableParallelism": true,
"incremental": true,
"watchOptions": {
"alwaysWatch": false,
"watchPhases": ["_phase:build"]
}
},
{
"commandKind": "phased",
"name": "test",
"phases": ["_phase:build", "_phase:test"],
"enableParallelism": true,
"incremental": true,
"watchOptions": {
"alwaysWatch": false,
"watchPhases": ["_phase:build", "_phase:test"]
}
}
]Rush 会自动为具有
watchOptions
属性的任何命令添加一个新的布尔标志--watch
。使用项目选择参数调用该命令,该参数选择所有
D
的依赖项,但不选择D
本身# Build everything that D depends on (but not D itself),
# and keep doing that in an endless loop:
$ rush build --watch --to-except D然后,在应用程序文件夹中启动您的开发服务器
# Start Webpack's dev server in the folder for project D
# (which is the web application in this example):
$ cd apps/D
$ heft start # <-- or your own "npm run start" equivalent here
批量命令的监视模式
在 command-line.json 配置文件中添加一个自定义命令。继续上面的示例,我们的自定义命令将被称为
"build:watch"
。重要的设置是"incremental"
和"watchForChanges"
common/config/rush/command-line.json
. . .
"commands": [
{
"name": "build:watch",
"commandKind": "bulk",
"summary": "Build projects and watch for changes",
"description": "For details, see the article \"Using watch mode\" on the Rush website: https://rush.node.org.cn/",
// use incremental build logic (important)
"incremental": true,
"enableParallelism": true,
// Enable "watch mode"
"watchForChanges": true
},
. . .为每个 Rush 项目向**package.json** 文件添加一个
"build:watch"
脚本。(PR #2298 旨在简化此步骤,因为这些项目的"build:watch"
将与"build"
相同。最终,还可以将这些定义合并到共享的 rig 包 中。)如果您使用的是 Heft,您的脚本将如下所示
package.json
. . .
"scripts": {
"build": "heft build --clean",
"build:watch": "heft build"
}
. . .使用项目选择参数调用该命令,该参数选择所有
D
的依赖项,但不选择D
本身# Build everything that D depends on (but not D itself),
# and keep doing that in an endless loop:
rush build:watch --to-except D最后,在应用程序文件夹中启动您的开发服务器
# Start Webpack's dev server in the folder for project D
# (which is the web application in this example):
cd apps/D
heft start # <-- or your own "npm run start" equivalent here在某些情况下,
--changed-projects-only
命令可以与"watchForChanges"
相结合,以实现更快的监视。仅构建已更改的项目 部分解释了其工作原理以及何时合适。
**“实验性”**
"watchForChanges"
功能仍处于早期阶段。欢迎您提供反馈!GitHub 问题 #1202 跟踪了其他工作项目,以及 William Bernting 的原始开发计划。
社区解决方案
Rush 社区分享了一些有趣的解决此问题的替代方法,这些方法也很有用
@telia/rush-select 是一个交互式仪表板,用于监视 Rush 项目并选择要重建的项目。
rush-dev-watcher 是来自 Daniel Imfeld 的一个简单但实用的脚本,它执行初始构建,然后启动多个监视器。