post-install-cmd在生产环境默认不执行,因Composer v2.2+在--no-dev模式下默认禁用所有scripts以保障安全;需显式启用--scripts或改用composer run-script调用独立部署脚本。

为什么 post-install-cmd 在生产环境默认不执行
因为 Composer 为安全起见,从 2.2 版本起默认禁用所有脚本(包括 post-install-cmd)在 --no-dev 模式下运行。这不是 bug,是设计行为——防止开发阶段写的钩子在生产环境意外触发敏感操作(比如清 Redis、重置数据库)。
常见错误现象:composer install --no-dev 后,php artisan config:clear 没执行,缓存没清,新配置不生效;本地能跑,线上报错。
- 必须显式启用:加
--no-dev --no-scripts是默认行为,要执行钩子就得反向加--no-dev --scripts - 但注意:
--scripts会同时执行pre-*和post-*,而pre-install-cmd若失败(如权限检查不通过),整个install就中断 - 更稳妥的做法是把关键部署动作拆成独立 script,例如
"deploy:finish": "@php artisan cache:clear && @php artisan view:cache",然后用composer run-script deploy:finish --no-dev单独调用
秒级回滚依赖于 vendor 目录的原子切换
所谓“秒级回滚”,本质不是重装依赖,而是切换已预构建好的 vendor/ 快照目录。CI/CD 流水线应在构建阶段就生成带时间戳或 commit hash 的 vendor 存档(如 vendor-abc1234),并保留最近 3–5 个版本。
部署脚本不直接 rm -rf vendor && composer install,而是:
- 将新
vendor-xyz7890软链接到当前vendor(ln -sf vendor-xyz7890 vendor) - 旧
vendor-abc1234仍保留在磁盘上,回滚只需再切一次软链(ln -sf vendor-abc1234 vendor) - 务必确保 Web 服务器用户(如 www-data)对目标
vendor目录有读权限,且软链目标路径不跨文件系统(否则unlink失败)
如果用 Deployer,它的 deploy:symlink 任务天然支持该模式;自建脚本则需手动控制软链 + chown -R www-data:www-data vendor-*。
vendor 清理不是可选项,而是上线前强制步骤
composer install --no-dev --optimize-autoloader 只是起点,不是终点。它不会删掉 vendor/bin/、vendor/*/tests/、vendor/*/docs/ 或 vendor/composer/installed.json —— 这些残留可能被利用来探测技术栈、执行测试工具甚至 RCE(如某些包的 bin 脚本未设权限校验)。
工作流任务拆解与模型编排技能。使用场景:(1) 收到复杂工作任务需要拆解为可执行步骤,(2) 需要为不同步骤选择最合适的模型,(3) 需要跟踪工作流进度和模型使用情况,(4) 长时间任务卡住需要问题诊断和解决方案。
推荐清理命令(Linux/macOS):
find vendor -depth ( -name 'tests' -o -name 'Tests' -o -name 'test' -o -name 'Test' -o -name '.git' -o -name 'phpunit.xml' -o -name 'phpstan.neon' ) -prune -exec rm -rf {} +
更安全的做法是在 CI 阶段用 rsync 或 cp --exclude 复制白名单内容,而非在目标机上 find 删除——避免误删或漏删。
特别注意:vendor/composer/autoload_classmap.php 是 --optimize-autoloader 生成的,但若项目用了 classmap 类型 autoload,还需确认 composer dump-autoload --classmap-authoritative 是否成功,否则类加载可能 fallback 到文件扫描,失去性能优势。
Docker 环境下 vendor 缓存与多阶段构建的配合要点
在 Docker 中,不能靠 “宿主机缓存 vendor” 提速,因为容器是隔离的。真正有效的加速来自两层:构建时的 layer 缓存 + 运行时的只读 vendor 挂载。
关键点:
- 多阶段构建中,第一阶段(
AS composer)必须COPY composer.json composer.lock .在RUN composer install之前,否则无法利用 Docker 构建缓存 - 第二阶段不要
RUN composer dump-autoload—— 它应已在第一阶段完成;只需COPY --from=composer /app/vendor /app/vendor,再COPY . . - 若用
--classmap-authoritative,必须确保所有类都已被收录进 classmap,否则容器启动即报Class not found;建议在第一阶段末尾加php -r "var_dump(class_exists('App\Http\Kernel'));"做简单验证
复杂点在于:当 composer.lock 变更时,Docker 构建会重新拉取全部依赖,但你无法控制哪些包走 dist、哪些走 source —— 所以始终用 --prefer-dist,并确保私有仓库配置通过 COMPOSER_AUTH 注入,而非写死在 auth.json 里。

















