post-install-cmd仅在composer install执行且composer.lock不存在或已过期时触发;若lock文件存在且匹配,则不执行。

post-install-cmd 什么时候真正触发
它只在 composer install 执行且 composer.lock 不存在、或已过期(即依赖版本有变更但 lock 未更新)时触发。如果 lock 文件存在且内容匹配当前 composer.json,那 install 就直接复用 vendor 和 lock,post-install-cmd 完全不跑。
常见错误现象:composer install 后脚本没执行,但 composer run-script post-install-cmd 手动能跑通——基本就是锁文件“太新”了,事件压根没被调度。
- 想每次
install都执行?别只靠post-install-cmd,得同时注册post-update-cmd,或者改用更稳的post-autoload-dump -
post-install-cmd不适合放耗时操作(比如全量数据库迁移),CI 环境下容易超时 - 本地开发中反复
rm composer.lock && composer install来“强制触发”,是错觉,不是可靠方案
post-autoload-dump 是最可靠的“每次生效”钩子
只要 composer install、composer update 或 composer dump-autoload 运行过,post-autoload-dump 就一定触发。它不依赖 lock 文件状态,只依赖自动加载文件是否被重生成——而这三者都必然触发该事件。
适用场景:清理缓存、生成配置文件、编译视图、刷新路由缓存等“只要代码结构变了就得重做”的任务。
- 示例配置:
"post-autoload-dump": ["php artisan config:clear", "php artisan route:clear"] - 注意:它的执行时机比
post-install-cmd稍晚,因为要等 autoload 文件写完才触发 - 如果你的脚本依赖刚安装的类(比如某个新包里的命令行类),
post-autoload-dump是唯一能确保 autoloader 已就绪的事件
pre- 和 post- 脚本的执行顺序不是对称的
比如 pre-update-cmd 和 post-update-cmd 看起来是一对,但它们触发条件不同:前者在依赖解析前就跑,后者在全部下载、安装、autoload 写入完成后才跑。中间可能穿插几十个 post-package-install 事件。
真实执行链(简化版,以 composer update 为例):
pre-update-cmd → pre-dependencies-solving → post-dependencies-solving → pre-package-install (每个包一次) → post-package-install (每个包一次) → pre-autoload-dump → post-autoload-dump → post-update-cmd
-
pre-package-install和post-package-install是按包逐个触发的,不是批量;你不能假设所有依赖都已就位 - 不要在
pre-*事件里删缓存或清数据库——此时旧包可能还没卸载,新包也没装上,环境处于中间态 -
post-root-package-install只在create-project时触发一次,和日常install/update无关
CI/CD 中脚本不执行的三个硬性原因
不是脚本写错了,而是默认被禁用了。几乎所有 CI 流水线(GitHub Actions、GitLab CI、Laravel Envoyer)默认加了 --no-scripts 参数,为的是跳过非必要步骤提速。
- 检查你的 CI 配置里
composer install命令是否含--no-scripts或-n;删掉,或显式加上--scripts - Docker 构建中常见写法:
composer install --no-interaction --no-scripts→ 改成composer install --no-interaction - 某些托管平台(如 Laravel Forge)部署脚本默认禁用,需手动在部署钩子里补上
--scripts
最易忽略的一点:事件脚本只在根项目 composer.json 中定义才有效,vendor 里任何包写的 post-install-cmd 都会被 Composer 主动忽略——这是设计使然,不是 bug。











