Composer install --no-dev 是标准部署做法,它跳过 require-dev 仅按 lock 文件安装生产依赖,需配合 --optimize-autoloader 和 --classmap-authoritative,并确保 lock 文件无 dev 条目且 autoload 配置已清理。

Composer 默认会把 require 和 require-dev 区块里的包一股脑全装上。但到了上线部署这一步,你肯定不想在生产服务器上看到 phpunit、mockery 或者 larastan 这类开发依赖的身影——它们不仅白白占用磁盘和网络带宽,还可能埋下安全风险,甚至引发自动加载冲突。
为什么 composer install --no-dev 是标准做法
这个命令的核心作用,是跳过 require-dev 部分,只安装 require 中声明的生产依赖。但有个关键前提:它只在 composer.lock 文件存在时才按预期工作。本质上,它不是简单地“忽略开发包”,而是“严格依据 lock 文件,还原一个纯净的生产环境依赖树”。如果项目没提交 lock 文件,或者本地的 composer.json 与 lock 文件内容不一致,那么使用 --no-dev 反而可能导致意想不到的行为。
- 在 CI/CD 流水线中,必须加上
--no-dev,否则测试工具链很可能被意外打包进生产镜像。 - 启动 PHP-FPM 容器前,标准的做法是执行
composer install --no-dev --optimize-autoloader。 - 需要警惕的是,如果项目通过
autoload-dev注册了测试专用的辅助类,那么在--no-dev模式下,这些类不会被自动加载,运行时一旦调用,就会直接抛出Class not found错误。
composer install vs composer update 的 --no-dev 行为差异
这里有个容易踩坑的区别:composer install --no-dev 是安全且可重复的操作;而 composer update --no-dev 则会重新解析 require 中的依赖并更新 lock 文件,但它不会去处理 require-dev 里的版本约束。这会导致一个隐患:lock 文件里可能残留旧的开发包信息,后续如果执行不带 --no-dev 的 composer install,这些包依然会被安装回来。
- 记住一个铁律:永远不要在生产环境运行
composer update,无论是否添加--no-dev选项。 composer update --no-dev的适用场景,是在开发机上生成一份纯净的生产环境 lock 文件。但完成后,务必手动检查确认 lock 文件中已彻底清除require-dev的相关条目。- 如何检查 lock 文件是否“干净”?一个简单的方法是运行
grep -A 5 "require-dev" composer.lock,如果命令输出为空,才算真正过关。
autoload 优化与 --no-dev 的配合要点
--no-dev 本身并不改变自动加载的行为,但它能让 --optimize-autoloader(简称 -o)选项的效果更好。原因很简单:移除了开发相关的类之后,生成的 vendor/composer/autoload_classmap.php 文件体积会更小,PHP 在查找类路径时的速度自然就更快了。
- 推荐的组合命令是:
composer install --no-dev --optimize-autoloader --classmap-authoritative。 --classmap-authoritative这个选项会告诉自动加载器:“所有类都在 classmap 里了,别再去文件系统里费力查找。” 这对于没有使用autoload-dev配置的项目来说,尤其稳妥。- 这里有个细节:如果项目通过
psr-4将命名空间映射到了tests/目录(例如 Lara vel 中常见的"Tests\": "tests/"),那么即使加了--no-dev,这些映射关系仍然会保留在自动加载配置中。要解决这个问题,需要手动将其移入"autoload-dev"区块,或者直接删除。
话说回来,很多团队容易陷入一个误区:把 --no-dev 当成了万无一失的“防错开关”,却忽略了同步清理 autoload 配置,或者忘记验证 lock 文件的实际内容。一旦某次 composer update 操作意外地将开发包的版本信息写入了 lock 文件,那么下一次部署时,这些包就可能被悄悄地带入生产环境。这才是关键所在。
