如何检测tsc --watch模式下多项目首次构建完成时机?
不用关--watch模式就能拿到首次构建完成的时机,直接用下面的方法就行:
方案1:抓tsc watch的输出日志当触发信号
tsc --watch每次编译走完(包括第一次编译)都会往标准输出打固定内容的日志,首次编译成功的日志格式如下:
[HH:MM:SS] Found 0 errors. Watching for file changes.
后台启动Tokens和ModulesCollection的构建进程时,监听它们的输出,匹配到对应日志就给对应项目打完成标记,等两个项目的标记都齐了,再启动Lexer的watch构建即可。
下面是不需要额外装依赖的bash脚本,可直接使用:
#!/bin/bash set -e BASE_DIR="UAA_Generators/JapaneseSyntax/ByNodeJS" TOKENS_DIR="$BASE_DIR/DataStructures/Tokens" MODULES_DIR="$BASE_DIR/DataStructures/ModulesCollection" LEXER_DIR="$BASE_DIR/Actuators/Lexer" tokens_done=0 modules_done=0 # 后台启动Tokens构建,监听首次完成信号 ( cd "$TOKENS_DIR" || exit 1 npm run "Incremental building" 2>&1 | while read -r line; do echo "[Tokens] $line" if [[ $line == *"Watching for file changes."* && $tokens_done -eq 0 ]]; then tokens_done=1 touch /tmp/tokens_build_done fi done ) & # 后台启动ModulesCollection构建,监听首次完成信号 ( cd "$MODULES_DIR" || exit 1 npm run "Incremental building" 2>&1 | while read -r line; do echo "[Modules] $line" if [[ $line == *"Watching for file changes."* && $modules_done -eq 0 ]]; then modules_done=1 touch /tmp/modules_build_done fi done ) & echo "等待Tokens、ModulesCollection首次构建完成..." # 轮询等待两个完成标记生成 while [ ! -f /tmp/tokens_build_done ] || [ ! -f /tmp/modules_build_done ]; do sleep 0.5 done rm -f /tmp/tokens_build_done /tmp/modules_build_done echo "前置依赖首次构建完成,启动Lexer构建..." cd "$LEXER_DIR" || exit 1 npm run "Incremental building"
这里默认匹配规则为只要出现
Watching for file changes.就算首次编译流程走完,不校验是否存在类型错误;如果需要等零错误再启动Lexer,把匹配字符串改回Found 0 errors. Watching for file changes.即可。脚本给每个子项目的输出加了前缀,不会出现三个项目日志混杂难以排查的问题。
方案2:使用带生命周期钩子的tsc封装工具
如果觉得自行写日志匹配逻辑麻烦,可以把原生tsc替换成带构建钩子的封装包,比如tsc-watch,它自带--onFirstSuccess参数,可直接指定首次构建成功后执行的命令,不需要手动解析日志,也不会因为后续tsc版本升级调整日志输出格式导致匹配失效。
用法很简单,安装依赖后,把Tokens和ModulesCollection的"Incremental building"脚本调整为:
rimraf Distributable && tsc-watch --onFirstSuccess "touch /tmp/%PROJECT_NAME%_build_done"
把%PROJECT_NAME%替换为对应项目标识(tokens或者modules)即可,后续等待标记、启动Lexer的逻辑和方案1完全一致,Lexer本身不需要修改,继续沿用原有watch脚本即可,完全不影响后续文件变更自动重编译的能力。
方案3:直接轮询构建产物
如果不想修改现有构建命令,可直接轮询两个项目Distributable输出目录下的核心文件,比如各自的入口js文件、类型声明文件,两个目标文件都生成即判定首次构建完成。
核心逻辑就是简单的循环判断:
while [ ! -f "$TOKENS_DIR/Distributable/index.js" ] || [ ! -f "$MODULES_DIR/Distributable/index.js" ]; do sleep 0.5 done
这个方法实现成本最低,但要注意选对判断用的特征文件,必须是构建流程最后生成的产物,不要选构建中途就会生成的临时文件,避免提前触发Lexer启动导致依赖缺失报错。
- 以上三个方案都不会破坏watch模式的自动重编译能力,完全匹配需求
- 如果在Windows环境运行,使用Git Bash或者WSL执行bash脚本即可,临时标记文件路径替换为Windows系统临时目录路径就可以正常运行
内容的提问来源于stack exchange,提问作者Takeshi Tokugawa YD

