Composer不发布代码,仅执行命令;“发布脚本”是将rsync、composer install等串为可复用scripts并显式触发;post-install-cmd在生产环境默认不执行,因--no-dev禁用dev钩子;关键部署动作应抽为独立脚本(如deploy:cache)并显式调用。

Composer 本身不发布代码,也不推送到服务器——它只负责按顺序执行你写的命令。所谓“发布脚本”,本质是把 rsync、composer install、权限修复、缓存清理这些操作串成可复用的 scripts,再靠 composer run-script 显式触发。
post-install-cmd 在生产环境默认不执行
这是最常踩的坑:你在本地 composer install 能清缓存、跑迁移,一上生产就静默跳过。原因很直接——--no-dev 默认禁用所有 dev 相关钩子,post-install-cmd 就属于这一类。
实操建议:
- 别依赖
post-install-cmd做关键部署动作,它不是为生产设计的 - 把真正要跑的逻辑(如
php artisan config:cache)抽成独立脚本名,比如deploy:cache - 部署时显式调用:
composer install --no-dev --optimize-autoloader && composer run-script deploy:cache - 检查是否误设了环境变量
COMPOSER_NO_DEV=1,它和--no-dev效果一致
rsync 同步必须排除 vendor/ 和 node_modules/
直接 rsync -avz ./ user@prod:/var/www/app/ 很危险:vendor/ 里可能含本地调试工具、敏感 token 或未清理的 .git 目录;node_modules/ 则体积大、平台相关,不该上传。
正确做法:
- 同步命令加
--exclude="vendor/" --exclude="node_modules/" --exclude=".git" - 目标机上必须重装依赖:
ssh user@prod 'cd /var/www/app && composer install --no-dev --optimize-autoloader --classmap-authoritative' - 前端构建产物(如
public/build/)应由 CI 构建后单独同步,不走rsync全量推
PHP 脚本比 shell 更可靠,但得加载 autoload
写 "clear-cache": "php artisan cache:clear" 看似省事,但一旦 artisan 路径错、PHP CLI 版本不一致、或 autoloader 没加载,就直接失败。
换成 PHP 脚本更稳:
- 脚本开头必须
require_once __DIR__ . '/../vendor/autoload.php'; - 用
getenv('APP_ENV')判断环境,避免生产误操作(比如if (getenv('APP_ENV') !== 'prod') { exit(1); }) - 敏感操作加执行防护:迁移前检查数据库连接,缓存清理前确认 storage/ 可写
- 不要用
php简写,改用php -d memory_limit=-1防止 CLI ini 限制内存
权限和用户隔离必须显式处理
部署用户(如 deploy)和 Web 服务用户(如 www-data)通常不同,chmod -R 755 storage/ 只是表面功夫,日志文件权限不对照样报 Permission denied。
建议分层设置:
- 目录(
storage/logs、storage/cache)设为755,属主www-data:www-data - 文件(
.env、storage/*.log)设为644或600 - 用
chown -R www-data:www-data storage/ bootstrap/cache/替代递归 chmod - 软链存储目录(如
storage/app/public → public/storage)要在部署后重建
真正的复杂点不在脚本怎么写,而在于每一步都得考虑「谁在运行」「当前目录在哪」「环境变量有没有污染」「失败后会不会残留半截状态」。越想一步到位写个巨长的 deploy 脚本,越容易卡在中间某步没回滚路径。拆成 sync、install、cache、chown 四个独立脚本,手动或 CI 分步调,才是线上稳住的底线。


















