生产环境 composer install 后脚本不执行,是因为 --no-dev 默认禁用 post-install-cmd 等钩子;需显式调用 composer run-script 或拆分关键逻辑到独立 script 并用 --no-dev 显式触发。

生产环境 composer install 后脚本不执行,不是配置漏了,而是默认被禁用——--no-dev 会连带跳过 post-install-cmd 等钩子,必须显式调用或拆分逻辑。
post-install-cmd 在部署机上为什么总不触发
它不是“装完就跑”,而是“装完且未禁用时才跑”。composer install --no-dev 默认关闭所有开发期事件钩子,包括 post-install-cmd 和 post-update-cmd。CI/CD 流水线里加了 COMPOSER_NO_DEV=1 或 --no-dev,但没补上 --no-scripts 的反向控制,就会误以为钩子该跑却没跑。
- 别依赖隐式触发:生产部署应主动调用
composer run-script deploy:post-install,而不是指望post-install-cmd自动生效 - 检查是否被全局禁用:运行
composer config --list | grep no-scripts,确认没意外启用COMPOSER_NO_SCRIPTS -
post-root-package-install和post-create-project-cmd不受--no-dev影响,适合做初始化类操作(如生成.env)
scripts 字段怎么写才真正生效
写错位置、命名不匹配、大小写混用,都会让脚本彻底静默失效。Composer 不报错,只当没这回事。
- 必须定义在
composer.json根层级的"scripts"对象里,不能嵌套进"extra"或缩进到"require"下面 - 脚本名区分大小写:
"Deploy:clear"和"deploy:clear"是两个不同命令;调用时必须完全一致,比如composer run deploy:clear - 数组值按顺序执行,失败即停:
"deploy:post": ["php artisan config:cache", "chmod 644 .env"]中第一条失败,第二条不会运行 - 用
composer run --list验证是否注册成功,这是唯一靠谱的检查方式
部署脚本里该用 shell 还是 PHP 文件
内联 shell 命令看着快,但跨平台差、错误难捕获、autoloader 不加载、权限和路径容易翻车;PHP 脚本可控性高得多。
- 优先封装成独立文件,例如
scripts/deploy-post.php,内容以require __DIR__ . '/../vendor/autoload.php';开头 - 用
getenv('APP_ENV')判断环境,避免生产误清缓存或执行迁移 - 敏感操作加防护:比如
if (getenv('APP_ENV') !== 'prod') { exit(1); } - 不要写
"php artisan cache:clear",改用"php scripts/deploy-post.php",后者可统一处理异常、日志、超时
Ansible 或 CI 中调用 Composer 脚本要注意什么
直接用 shell 模块跑 composer run 容易因 PATH、用户权限、PHP 版本不一致而失败;用官方模块更稳。
- Ansible 推荐
community.general.composer模块,它自动探测 PHP 路径、校验composer.json存在性,参数如no_dev: true、optimize_autoloader: true直接对应 - 若必须用
command模块,调用路径写死:/usr/local/bin/composer run deploy:post-install,别依赖$PATH - CI 环境中注意
CI=true可能影响某些包行为,脚本里加if [ "$CI" = "true" ]; then ... fi做兜底 - 权限问题最常出在
storage/和bootstrap/cache/:部署用户和 Web 用户不同,chown -R www-data:www-data必须显式执行,不能靠本地 chmod
真正卡住人的从来不是“怎么写脚本”,而是“谁在什么上下文里以什么权限执行它”——工作目录、环境变量、PHP CLI 配置、用户 UID/GID,四个点里错一个,post-install-cmd 就会看起来像没生效。











