配置监视
从 TypeScript 3.8 开始,TypeScript 编译器公开了用于控制其如何监视文件和目录的配置。在此版本之前,配置需要使用环境变量,这些变量仍然可用。
背景
编译器的 --watch 实现依赖于 Node 的 fs.watch 和 fs.watchFile。这些方法各有优缺点。
fs.watch 依赖文件系统事件来广播被监视文件和目录的变化。此命令的实现依赖于操作系统且不可靠——在许多操作系统上,它无法按预期工作。此外,某些操作系统限制了可以同时存在的监视数量(例如,某些 Linux 发行版)。在大型代码库中大量使用 fs.watch 可能会超过这些限制并导致不良行为。然而,由于此实现依赖于基于事件的模型,CPU 使用率相对较低。编译器通常使用 fs.watch 来监视目录(例如,编译器配置文件包含的源目录、模块解析失败的目录等)。TypeScript 使用这些来补充单个文件监视器的潜在故障。然而,此策略有一个关键限制:在 Windows 和 macOS 上支持递归监视目录,但在 Linux 上不支持。这表明需要额外的文件和目录监视策略。
fs.watchFile 使用轮询,因此会消耗 CPU 周期。然而,fs.watchFile 是迄今为止可用于订阅感兴趣文件和目录事件的最可靠机制。在此策略下,TypeScript 编译器通常使用 fs.watchFile 来监视源文件、配置文件以及基于引用语句似乎缺失的文件。这意味着使用 fs.watchFile 时 CPU 使用率的高低程度直接取决于代码库中监视的文件数量。
使用 tsconfig.json 配置文件监视
配置监视行为的建议方法是通过 tsconfig.json 中新的 watchOptions 部分。我们在下面提供了一个配置示例。有关可用设置的详细说明,请参阅下一节。
{
// 一些典型的编译器选项
"compilerOptions": {
"target": "es2020",
"moduleResolution": "node"
// ...
},
// 新:文件/目录监视的选项
"watchOptions": {
// 对文件和目录使用原生文件系统事件
"watchFile": "useFsEvents",
"watchDirectory": "useFsEvents",
// 当文件更新频繁时,更频繁地轮询文件
"fallbackPolling": "dynamicPriority",
// 不合并监视通知
"synchronousWatchDirectory": true,
// 最后,两个额外的设置,用于减少可能跟踪的文件数量
"excludeDirectories": ["**/node_modules", "_build"],
"excludeFiles": ["build/fileWhichChangesOften.ts"]
}
}有关更多详细信息,请参阅 Typescript 3.8 的发布说明。
使用环境变量 TSC_WATCHFILE 配置文件监视
| 选项 | 描述 |
|---|---|
PriorityPollingInterval | 使用 fs.watchFile,但对源文件、配置文件和缺失文件使用不同的轮询间隔 |
DynamicPriorityPolling | 使用动态队列,其中频繁修改的文件以较短的间隔轮询,未更改的文件以较低频率轮询 |
UseFsEvents | 使用 fs.watch。在限制活动监视数量的操作系统上,当无法创建监视器时,回退到 fs.watchFile。 |
UseFsEventsWithFallbackDynamicPolling | 使用 fs.watch。在限制活动监视数量的操作系统上,回退到动态轮询队列(如 DynamicPriorityPolling 中所述) |
UseFsEventsOnParentDirectory | 在包含文件的父目录上使用 fs.watch(这是一种折衷方案,导致 CPU 使用率低于纯 fs.watchFile,但可能准确性较低)。 |
| default (未指定值) | 如果环境变量 TSC_NONPOLLING_WATCHER 设置为 true,则使用 UseFsEventsOnParentDirectory。否则,使用 fs.watchFile 监视文件,任何文件的超时时间为 250ms。 |
使用环境变量 TSC_WATCHDIRECTORY 配置目录监视
对于本身不支持递归目录监视的平台(即非 macOS 和 Windows 操作系统),通过使用 TSC_WATCHDIRECTORY 选择的不同选项,为每个子目录递归创建目录监视器来支持目录监视。
注意: 在支持原生递归目录监视的平台上,TSC_WATCHDIRECTORY 的值将被忽略。
| 选项 | 描述 |
|---|---|
RecursiveDirectoryUsingFsWatchFile | 使用 fs.watchFile 监视包含的目录和子目录。 |
RecursiveDirectoryUsingDynamicPriorityPolling | 使用动态轮询队列轮询包含的目录和子目录的变化。 |
| default (未指定值) | 使用 fs.watch 监视包含的目录和子目录。 |