post-install-cmd 仅在 composer.lock 不存在或过期时触发,非每次 install 都执行;需每次运行应改用 post-update-cmd 或自定义脚本显式调用。

Composer 的 post-install-cmd 不是“安装后自动执行任意命令”的万能钩子,它只在 composer install 且 composer.lock 不存在或过期时触发;想每次 install 都跑,得用 post-update-cmd 或统一走 scripts + 手动调用。
post-install-cmd 触发条件很具体
很多人以为只要运行 composer install 就会执行 post-install-cmd,实际不是:
- 如果项目已有有效的
composer.lock(即依赖版本已锁定),composer install只是解包,不会触发post-install-cmd - 只有首次克隆项目、删了
composer.lock后重装,或 lock 文件里记录的依赖与composer.json不一致(比如改了 require)导致 Composer 重生成 lock 时,才会触发 - 相比之下,
post-update-cmd在composer update和composer install --update时都更稳定触发
在 composer.json 里正确声明脚本
脚本必须写在 "scripts" 字段下,键名严格为 "post-install-cmd"(注意大小写和连字符):
{
"scripts": {
"post-install-cmd": [
"@php -r "echo 'Install done.\n';"",
"php artisan optimize:clear",
"npm install"
]
}
}
几点关键说明:
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 值可以是字符串(单条命令)或字符串数组(多条顺序执行),推荐数组,便于维护
- 以
@开头的命令(如@php)表示调用当前 Composer 自带的脚本别名,避免路径问题 - 外部命令如
npm install要求系统 PATH 中存在npm,CI 环境需提前确认 Node.js 已安装 - PHP 脚本建议用
php -f script.php显式指定,不用./script.php(可能无执行权限)
常见失败原因:权限、路径、执行时机
脚本看似配置对了,却静默失败或报错,通常卡在这几个点:
-
sh: 1: npm: not found→ 容器或 CI 镜像没装 Node.js,不能只靠本地有就认为线上也有 -
Permission denied: ./artisan→ Laravel 的artisan缺少可执行位,应改用php artisan ... - 脚本中引用的相对路径(如
../config/app.php)在不同工作目录下失效 → 始终用__DIR__或getcwd()动态拼接,或改用 Composer 提供的$vendorDir/$binDir变量(需配合composer run-script的变量替换机制) - 想在脚本里读取
composer.json内容?别手动file_get_contents,用ComposerInstalledVersions::getRawData()(v2+)或解析vendor/composer/installed.json更可靠
替代方案:用自定义脚本 + 显式调用更可控
如果业务逻辑复杂,或需要每次 install 都执行(不管 lock 是否变化),不如绕开钩子语义,直接定义一个可复用的脚本:
{
"scripts": {
"setup": [
"@php -r "echo 'Running setup...\n';"",
"php artisan migrate --force",
"npm ci && npm run build"
],
"post-install-cmd": "@setup",
"post-update-cmd": "@setup"
}
}
这样既能被钩子触发,也能被人工执行:composer run-script setup。调试时也方便单独跑,不用反复删 composer.lock。
真正难的不是写几行命令,而是判断「这个操作到底该在哪个生命周期发生」——比如生成 autoload、清理缓存、编译前端资源,各自对 lock 文件是否变更、是否需要全量重装,敏感度完全不同。

















