Monorepo多包开发watch模式无法感知上游依赖变更问题求解
问题根因
c包和web包无法感知上游依赖变更,是三个默认机制共同导致的:
- 所有构建工具的watch模式默认仅监听包自身的源码目录,默认规则会直接跳过
node_modules下的所有文件监听——毕竟正常第三方npm包安装后不会变动,全量监听会带来无意义的性能开销。 - 用yarn+lerna管理依赖时,包间依赖是通过软链指向本地包目录实现的,而rollup、webpack依赖的底层监听库chokidar、watchpack默认不会跟随软链追踪真实文件的变更,Windows环境下这个问题会更明显:NTFS软链的路径识别和类Unix系统存在差异,不开对应配置根本识别不到软链目标的改动。
- watch模式的构建速度更快确实和缓存有关:启动时构建工具会一次性解析全量依赖树、缓存所有模块的导出内容,后续仅重新编译自身源码的变更文件,不需要重复遍历依赖;但这个缓存机制默认不会主动校验
node_modules下的依赖文件是否更新,上游包重新构建输出的新内容根本进不了当前运行进程的缓存,自然不会触发重编译。
配置调整方案
按改造成本从低到高选择即可,都能实现链式自动重构建。
方案1:修改现有构建工具的监听配置,无新增依赖
针对rollup构建的库(a/b/c包)
在每个包的rollup配置中补充watch规则,放开对本地monorepo依赖包的监听限制,开启软链追踪:
// 以c包的rollup.config.js为例 export default { input: 'src/index.ts', // 保留原有output、plugin配置 watch: { // 排除所有第三方node_modules包,但保留对本地a、b包的监听 exclude: ['node_modules/**', '!node_modules/a/**', '!node_modules/b/**'], chokidar: { followSymlinks: true, // 强制跟随软链识别真实文件变更,适配Windows环境 depth: 10 // 开启足够的深度监听,避免多层软链识别失效 } } }
如果包的依赖层级更深,记得把对应上游包加到exclude的排除规则里。
针对webpack构建的web应用
修改webpack配置,把本地monorepo包移出默认的持久化缓存托管路径,补充监听规则:
// web包的webpack.config.js module.exports = { // 保留原有entry、plugin、loader配置 snapshot: { // 仅对非本地monorepo的第三方依赖做持久化缓存 managedPaths: [/^(.+?[\\/]node_modules[\\/])(?!a|b|c)/] }, watchOptions: { followSymlinks: true, // 忽略第三方node_modules包,监听a/b/c三个本地依赖包的变更 ignored: ['**/node_modules/**', '!**/node_modules/a/**', '!**/node_modules/b/**', '!**/node_modules/c/**'] } }
改完后重启所有watch进程,a包变更后会依次触发c、web的自动重编译,不需要手动操作。
方案2:用lerna原生能力统一管理监听,不需要单独改每个包的构建配置
lerna 6.0及以上版本自带lerna watch能力,会自动识别monorepo的依赖拓扑关系,某个包变更后自动按依赖顺序触发所有下游包的增量构建。
直接在根目录的package.json添加dev脚本即可:
{ "scripts": { "dev": "lerna watch -- lerna run build --scope=$LERNA_PACKAGE_NAME --include-dependents" } }
执行yarn dev启动后,不需要再分别给每个包单独启动watch进程:当修改a包源码,lerna会自动按a -> c -> web的顺序触发三个包的构建,全程不需要手动重启进程。
如果需要保留每个包原有的watch模式增量编译速度,可以给对应包的build命令加上--watch参数,lerna会自动处理进程调度,不会重复启动监听。
常见排错点
如果改完配置还是偶发不触发变更,直接删掉根目录和所有子包下的node_modules/.cache目录后重启,旧的构建缓存会导致变更识别失效。
内容的提问来源于stack exchange,提问作者helt
相关产品推荐
相关产品推荐

