Composer的scripts可通过显式指定工作目录(如chdir('modules/user'))并调用composer run或php artisan module:run来统一操作多模块,避免cd &&链式执行导致的路径和环境问题。

如何用 scripts 触发多模块的统一操作
Composer 本身不感知“模块”,但你可以用 scripts 把多个模块的重复动作串起来。比如每个模块都有自己的 composer.json,又都需跑测试、清缓存、生成 autoload —— 这些不能靠主项目自动传播,得手动调度。
常见错误是直接在根 composer.json 的 scripts 里写 cd modules/user && composer test,结果路径出错或子 shell 环境丢失。正确做法是显式指定工作目录并捕获失败:
- 用
php -d variables_order=EGPCS -r "chdir('modules/user'); passthru('composer run test --no-ansi');"确保子命令在对应目录执行 - 避免用
&&链式执行:一旦某个模块失败,后续模块不会跳过,也不报错;改用脚本封装并检查 exit code - 如果模块使用 Laravel-Modules,优先调用
php artisan module:run user:test(需模块内实现该命令),比直调composer更稳定
post-update-cmd 能否自动同步所有模块的依赖?
不能。主项目的 post-update-cmd 只作用于自身 vendor/ 和 composer.json,对子模块目录下的 composer.json 完全无感。你看到的“模块更新了”其实是假象——它们只是被主项目通过 path 仓库软链进来,自身依赖并未重装。
真正需要同步时,必须显式遍历模块目录并触发安装:
- 在根
scripts中定义"sync-modules": ["for d in modules/*/; do (cd \"$d\" && composer install --no-dev --quiet); done"] - 注意:
--no-dev很关键,否则子模块的require-dev会污染主项目环境 - 若模块间有交叉依赖(如
user依赖auth),要确保repositories配置已包含全部 path,并且版本约束用"*"或"dev-main",避免因版本未命中导致安装跳过
为什么自定义脚本里调用 php artisan 常失败?
因为 php artisan 是 Laravel 特有的命令行入口,它依赖 autoload.php 和应用上下文。当从根项目脚本中进入子模块目录再执行 php artisan,加载的是子模块自己的 vendor/autoload.php(如果存在),而非主项目的完整环境,大概率报 Class 'App\Console\Kernel' not found。
安全做法是始终在项目根目录执行 php artisan,靠参数或选项定位模块:
- 用 Laravel-Modules 时:运行
php artisan module:enable user或php artisan module:migrate user,它内部会自动加载模块服务提供者 - 不用扩展时:在主项目
app/Console/Commands/ModuleTestCommand.php中封装逻辑,接收模块名参数,动态 require 模块内的测试启动器 - 切忌在脚本里写
cd modules/user && php artisan test—— 即使能跑,也绕过了 Laravel 的服务容器和配置加载机制
本地开发时,怎么让 scripts 自动监听模块文件变更?
Composer scripts 是一次性命令,没有内置监听能力。想实现“改了 modules/payment/src/ 就自动跑单元测试”,必须借助外部工具,不能只靠 Composer。
最轻量方案是组合 composer run-script 和 inotifywait(Linux/macOS)或 fswatch:
- 写一个 shell 脚本
watch-modules.sh:inotifywait -m -e modify,create,delete modules/ --format '%w%f' | while read file; do composer run test-module -- --module=$(basename $(dirname $file)); done - 在
scripts中定义"test-module": ["php tests/run-module-test.php"],由 PHP 脚本解析--module参数并切换到对应目录执行phpunit - 注意:不要把监听逻辑塞进
composer.json的scripts字段——它不是进程管理器,起完就退出
真正的复杂点在于模块边界:一个文件变更可能影响多个模块的接口契约,而 scripts 无法做跨模块影响分析。这时候该上 monorepo 工具(如 Nx 或 Lerna 的 PHP 移植版),而不是硬撑 Composer 脚本。


















