composer install --no-dev 是生产部署强制前提,它跳过 require-dev 包及其传递依赖、autoload-dev 映射和 @dev 脚本,需配合 --optimize-autoloader 与 --classmap-authoritative 并确保 composer.lock 无 dev 条目。

composer install --no-dev 是唯一可靠的方式,它不是“建议”,而是生产部署的强制前提。不加这个参数,phpunit、phpstan、laravel-debugbar 这类包会照装不误——它们不会因为服务器上没写 require-dev 就自动消失。
为什么 composer install --no-dev 有时没效果
根本原因不是命令写错了,而是 composer.lock 文件本身已“污染”:它记录了 require-dev 中的包(比如上次用 composer update 生成的)。此时 --no-dev 会被忽略,甚至报错 dev dependencies not found。
- 验证方法:运行
grep -A 5 "require-dev" composer.lock,输出非空就说明 lock 文件含 dev 条目 - 修复方式:在干净环境(无
vendor/、无旧lock)执行composer update --no-dev --lock,再提交新composer.lock - CI/CD 中必须先清理缓存:比如
git clean -xffd vendor/,否则 Docker 构建可能复用带 dev 包的 layer
--no-dev 实际跳过哪些东西
它不只是删掉 require-dev 列表里的包,而是一整套过滤链:
- 跳过
require-dev中所有包及其全部传递依赖(例如phpunit/phpunit带来的sebastian/exporter也不会进vendor/) - 不加载
autoload-dev配置——像"Tests\": "tests/"这种映射不会注册,new TestsFooTest()必然触发Class not found - 跳过
scripts中标记为@dev的钩子(如post-autoload-dump里调用phpstan的命令会静默跳过)
配套参数不能少:性能和安全都要兼顾
--no-dev 解决“装什么”,但不解决“怎么装得快、装得稳”。线上必须组合使用:
-
--optimize-autoloader(或-o):生成扁平化类映射,减少文件系统查找;但注意——若代码用了动态类名拼接(如new $className),且该类不在 autoload map 里,就会报错 -
--classmap-authoritative:告诉 autoloader “所有类都在 classmap 里,别再去磁盘找”,配合--no-dev更稳妥(因为 dev 类已被排除,classmap 更干净) -
--no-scripts和--no-interaction:避免部署卡在交互提示或执行前端构建等无关操作
真正容易被忽略的是 autoload-dev 映射残留问题:即使没装 phpunit,只要 vendor/autoload.php 里还保留着 tests/ 的 PSR-4 映射,class_exists('TestsFooTest') 仍可能返回 true——这会让某些条件判断逻辑意外通过,埋下线上隐患。











