使用Melos时build_runner跨包AssetNotFoundException问题排查
问题分析与解决
两种构建方式的核心差异
- Melos默认执行逻辑:
melos run build_runner会为每个包启动独立子进程执行build_runner,默认不清理旧缓存,也不会主动同步跨包的生成文件依赖状态。第一次执行时,app包的build_runner缓存可能还停留在sdk未生成代码的旧快照,就算sdk刚生成了.g.dart/.freezed.dart,app的构建进程也读不到。 - 自定义bash脚本:先执行
build_runner clean清空所有包的.dart_tool/build缓存,再按sdk→app的顺序构建。此时app的build_runner是从头解析依赖,能直接读取到sdk刚生成的文件,没有旧缓存干扰。
报错根源
- build_runner缓存过期:首次用Melos构建时,app包的build_runner缓存保留了旧的依赖元数据,认为sdk没有那些生成文件,即使本地文件已经存在,也会触发
AssetNotFoundException。 - 子进程文件系统隔离:Melos给每个包开独立子进程,sdk生成文件后,app的子进程没及时感知到文件变化,Dart的包解析器也没刷新依赖状态。
- 依赖顺序未强制:如果Melos脚本没配置按依赖顺序执行,可能出现app先于sdk构建的情况(即使手动选了sdk,缓存问题依然存在)。
修复方案
方案1:修改Melos脚本,强制按依赖顺序+清理冲突文件
在根目录melos.yaml中更新build_runner脚本:
scripts: build_runner: run: melos exec -s "dependencies" -- "dart run build_runner build --delete-conflicting-outputs" description: 按依赖顺序执行build_runner,自动清理冲突的旧生成文件
-s "dependencies":强制按包的依赖层级执行(先构建被依赖的sdk,再构建依赖它的app)--delete-conflicting-outputs:每次构建时自动清理旧的生成文件,避免缓存干扰
方案2:先统一清理缓存,再构建
如果方案1无效,先清理所有包的构建缓存,再按顺序执行:
scripts: build_runner_clean: run: melos exec -- "dart run build_runner clean" description: 清理所有包的build_runner缓存 build_runner: run: | melos run build_runner_clean melos exec -s "dependencies" -- "dart run build_runner build" description: 先清理缓存,再按依赖顺序执行build_runner
方案3:手动刷新Dart包缓存
偶尔出现缓存未同步时,先执行以下命令再跑Melos构建:
dart pub get
确保所有包的依赖元数据是最新的。
验证步骤
- 删除所有包下的
.dart_tool/build目录,模拟首次构建场景 - 执行修改后的
melos run build_runner,确认sdk和app都能正常构建 - 重复执行多次,检查是否不再触发
AssetNotFoundException
内容的提问来源于stack exchange,提问作者Marcin Kapusta
相关产品推荐
相关产品推荐

