post-install-cmd并非每次composer install都执行,仅当composer.lock不存在或过期时触发;若lock有效且依赖未变,则静默跳过。

为什么 composer install 后脚本会多跑一遍?
因为 Composer 默认在 install 和 update 两个命令后都触发 post-install-cmd 和 post-update-cmd。而 install 在锁文件存在时,本应跳过依赖解析,却仍会执行所有 scripts——这是设计行为,不是 bug。
常见现象:本地 composer install 后自动跑了 php artisan optimize:clear 或 npm run build,CI 环境里重复构建、拖慢流水线。
- 检查是否误将脚本同时注册在
post-install-cmd和post-update-cmd里 -
composer install --no-scripts可临时跳过,但不解决根本问题 - 真正需要区分的是「首次安装」和「依赖未变时的重装」,但 Composer 原生不提供该钩子
用 COMPOSER_COMMAND 环境变量做轻量判断
Composer 从 2.2 开始在执行脚本时注入 COMPOSER_COMMAND 环境变量,值为当前运行的命令名(如 install、update),可直接在脚本中读取。
适用于 shell 脚本或 PHP 脚本入口,无需额外依赖:
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
#!/usr/bin/env php
<?php
if (getenv('COMPOSER_COMMAND') === 'update') {
echo "Running post-update tasks...\n";
// 执行 vendor 重建后才需的操作,如生成 classmap、清理缓存
} else {
echo "Skipping post-install tasks (no dependency change)\n";
// 不执行耗时操作,比如 npm build、php artisan config:cache
}
- 注意:该变量仅在
scripts执行期间存在,PHP CLI 环境下可用getenv(),shell 脚本中直接用$COMPOSER_COMMAND - 不要依赖
COMPOSER_DEV_MODE判断开发环境,它和脚本触发时机无关 - 如果脚本是通过
php -r写的单行命令,记得加引号包裹,避免 shell 解析错误
composer.json 中的 scripts 配置怎么写才不踩坑?
别把所有逻辑塞进一个 post-install-cmd。拆开、按需注册,是最小侵入的优化方式。
- 只在真正需要时绑定:例如
post-update-cmd用于更新后重建 autoload,post-autoload-dump用于类映射变更后触发事件 - 避免在
post-root-package-install里调用php artisan,此时 Laravel 框架尚未加载完成,容易报Class not found - 若必须用 Artisan 命令,请确保
vendor/autoload.php已存在且路径正确,推荐用php ./artisan而非php artisan - Windows 下脚本路径分隔符易出错,统一用正斜杠或
dirname(__DIR__)动态构造
CI/CD 场景下更稳妥的替代方案
在 GitHub Actions、GitLab CI 等环境中,与其让 Composer 脚本兜底,不如把构建逻辑提到 pipeline 层面,由流程控制何时执行。
例如 GitLab CI 中:
install-dependencies:
script:
- composer install --no-interaction --prefer-dist
# 不触发任何 post-* 脚本
<p>build-assets:
needs: ["install-dependencies"]
script:</p><ul><li>npm ci && npm run build
rules:</li><li>if: $CI_PIPELINE_SOURCE == "merge_request_event" || $CI_COMMIT_TAG
- 这样能明确分离「依赖安装」和「资产构建」两个关注点
- 避免因本地
composer.json脚本变更意外影响 CI 行为 - 某些团队还会在
composer.lock变更检测后决定是否执行build步骤,比依赖 Composer 的钩子更可靠
最麻烦的地方往往不在脚本本身,而在于不同环境对 COMPOSER_COMMAND 的兼容性——旧版 Composer(composer.lock 修改时间或用 git status -s composer.lock 辅助判断。

















