生产环境不能直接运行 composer install,因其会因缺 git/proc_open/ext-zip、权限不足等卡死或中断,并触发 post-install-cmd 误操作、暴露 .env、autoload-dev 路径残留导致类加载失败;--no-dev 不足,需配合 --optimize-autoloader、--classmap-authoritative、--no-interaction、--prefer-dist、--no-scripts 在 CI/Docker 等一致环境中预构建 vendor 并整体同步。

生产环境为什么不能直接运行 composer install
因为线上机器不是开发机——它通常没装 git、没开 proc_open、缺 ext-zip,甚至 /root/.composer 不可写。一旦执行 composer install,轻则卡在 sh: git: not found,重则触发 post-install-cmd 生成新密钥、清空缓存、暴露 .env,或因平台版本不匹配直接中断。
composer install --no-dev 为什么还不够
它只跳过 require-dev 中的包,但不会清理已存在的 autoload 规则。比如某个包在 autoload-dev 里注册了 tests/ 路径,--no-dev 后这些路径仍留在 vendor/composer/autoload_psr4.php 中,类加载时可能 fallback 到不存在的目录,报错或白屏。
-
--optimize-autoloader(或简写-o)必须跟上:它重建autoload_classmap.php,把所有 PSR-4 类名直连文件路径,避免运行时反复stat() -
--classmap-authoritative是增强项:告诉 autoloader “类只可能在 classmap 里”,彻底禁用 fallback 扫描——性能提升明显,但要求 classmap 必须完整(新增类后得重跑 install) -
--no-interaction(-n)防卡死:跳过插件认证、私有源提示等交互环节 -
--prefer-dist强制走 zip 包:比 git clone 稳定,尤其跨区域网络 -
--no-scripts关掉钩子:防止post-install-cmd在线上误执行
离线部署必须做的三件事
离线 ≠ 把 vendor 目录 tar.gz 传上去就完事。真正安全的离线方案要确保构建环境与线上一致、锁文件干净、autoload 无残留。
- 先清空旧残留:
rm -rf vendor/ && rm -f composer.lock(Docker 构建尤其要防缓存错层) - 确保
composer.lock已提交且和代码分支匹配;否则composer install会退化为update - 在 CI 或 Docker 构建环境中执行:
composer install --no-dev --optimize-autoloader --classmap-authoritative --no-interaction --prefer-dist --no-scripts - 装完立刻清理冗余:
find vendor/ -name 'tests' -o -name 'Tests' -o -name 'test' -o -name 'Test' | xargs rm -rf,再删vendor/bin/和vendor/**/phpunit.xml - 验证:
composer show --dev应输出No dependencies installed for development
最容易被忽略的细节
很多人以为只要加了 --no-dev 就万事大吉,结果上线后还是报 Class 'TestsTestCase'。问题往往出在两个地方:
-
composer.lock文件本身含 dev 包记录:执行grep -A 5 "require-dev" composer.lock,输出非空说明 lock 文件不干净,需先在干净环境运行composer update --no-dev --lock并提交 -
autoload-dev的 PSR-4 映射未被清除:即使不装 dev 包,映射仍留在 autoloader 中;Laravel 默认的"Tests\": "tests/"就是典型,必须手动从composer.json移到autoload-dev区块,否则--no-dev无效











