生产环境部署应使用 composer install –no-dev 跳过 dev 依赖,既保全 composer.json 中的 require-dev,又避免安全风险与性能损耗;该参数不影响配置文件与 autoload-dev 的定义,仅控制安装行为。

composer install 时跳过 dev 依赖,但又不想删掉 composer.json 里的 require-dev
生产环境部署时,composer install 默认会装 require-dev 里的包(比如 phpunit、larastan),这既拖慢速度,又可能引入安全风险或冲突。直接删掉 require-dev 不现实——本地开发需要它,CI 也需要它跑测试。
正确做法是加 --no-dev 参数:
composer install --no-dev
这个参数只影响「安装行为」,不修改任何配置文件,也不影响后续 composer update 的默认行为。CI 脚本里务必加上;docker 构建镜像时也该加。
- 漏加
--no-dev是线上部署最常踩的坑,尤其在 laravel、symfony 项目里,symfony/debug或barryvdh/laravel-debugbar可能意外被装上并启用 -
--no-dev不影响autoload-dev的自动加载逻辑——只是不装包,不是禁用 autoload - 如果你用
composer install --optimize-autoloader --no-dev,还能进一步提速 autoloader
不同环境用不同 composer.json?别这么干
有人想搞 composer.prod.json 和 composer.dev.json,再用脚本替换——这是反模式。Composer 不支持多配置文件切换,强行替换会破坏 lock 文件一致性,导致本地和线上行为不一致,甚至出现「在我机器上能跑」的故障。
真正适配多环境的方式,是靠 COMPOSER_DEV_MODE 环境变量 + config.platform 控制依赖解析,而不是分裂配置文件。
-
COMPOSER_DEV_MODE=0会让 Composer 忽略require-dev(效果等同--no-dev),但极少用——不如直接加参数明确 -
config.platform才是关键:比如线上用 PHP 8.1,但你本地是 8.2,可以在composer.json里写:"config": { "platform": { "php": "8.1.0" } }这样
composer install就不会装那些只兼容 8.2 的包 - 平台配置必须写死版本号,不能写
^8.1或~8.1,否则无效
vendor/autoload.php 在不同环境加载行为不一致?检查 autoload 配置
有些包在 require-dev 里定义了 autoload-dev,比如测试工具注册自己的 PSR-4 命名空间。一旦你用了 --no-dev,这些 autoload 规则就失效了——但代码里如果硬写了 new TestsFooTest(),运行时就会报 class not found。
这不是 Composer 的 bug,而是 autoload 和依赖安装的边界没理清。
-
autoload-dev只在composer dump-autoload时生效,且仅当--dev(默认)开启时才写入vendor/autoload.php - 生产环境绝对不要引用
autoload-dev里的类,哪怕只是条件性class_exists(),都可能因类未加载而失败 - 想动态加载测试类?改用
require_once显式引入,别依赖 autoloader
如何让 CI/CD 自动区分 dev 和 prod 依赖?
CI 流水线里,测试阶段要全量装依赖,部署阶段只装 runtime 依赖——靠分支或 job 名称判断环境,不如靠明确指令。
推荐写法(以 github Actions 为例):
jobs:<br> test:<br> steps:<br> - run: composer install<br> deploy:<br> steps:<br> - run: composer install --no-dev --optimize-autoloader
注意两点:
- 不要在
deploy步骤里执行composer update——lock 文件应由test阶段生成并提交,确保部署时还原的是已验证的依赖树 -
--optimize-autoloader在 PHP >= 7.4 下显著提升类加载性能,但会禁用动态 classmap 发现,所以只在生产环境开 - 如果项目用了
composer-plugin-api类插件(如ocramius/package-versions),确认它是否在require里——不在的话,--no-dev后插件可能缺失,导致composer install报错
实际操作中,最易被忽略的是 platform 配置和 autoload-dev 的作用边界。很多人以为加了 --no-dev 就万事大吉,结果上线后因为某个 dev-only 类被间接引用而崩溃——问题不在命令,而在代码对环境假设太松。