线上部署必须加--no-dev,否则phpunit/phpunit等dev包会进入vendor/,引发rce、信息泄露、autoload膨胀、php-fpm启动慢及class not found等问题;它需配合--optimize-autoloader、--classmap-authoritative、--no-interaction和--prefer-dist才能兼顾安全与性能。

为什么线上部署必须加 --no-dev
不加 --no-dev,phpunit/phpunit、symfony/var-dumper、barryvdh/laravel-debugbar 这类包就会进线上 vendor/。这不是“多装几个包”的小事——它们自带反射、eval、调试入口点,曾多次触发 RCE 或敏感信息泄露;autoload 映射变大后,PHP-FPM worker 启动慢、OPcache 编译效率下降,甚至出现 Class not found 却查不到原因。
--no-dev 和其他参数的配合关系
--no-dev 只负责跳过 require-dev 字段声明的包,它不优化加载、不强制 classmap、也不跳过交互提示。单独用它,只是删包,没解决性能问题。
-
--optimize-autoloader(或-o):生成vendor/composer/autoload_classmap.php,把 PSR-4 映射转成静态数组,避免每次请求都stat()扫目录 -
--classmap-authoritative:告诉 autoloader “类只在 classmap 里”,彻底关掉 fallback 查找,这是防止Class not found的最后一道防线 -
--no-interaction:CI/CD 或 Docker 构建时没 TTY,不加这个可能卡在插件启用确认上 -
--prefer-dist:优先下 zip 包而非 git clone,减少网络不稳定导致的构建失败
正确组合是:composer install --no-dev --optimize-autoloader --classmap-authoritative --no-interaction --prefer-dist
哪些场景下 --no-dev 不生效
最常见失效不是参数写错,而是部署流程本身绕过了它:
工作流任务拆解与模型编排技能。使用场景:(1) 收到复杂工作任务需要拆解为可执行步骤,(2) 需要为不同步骤选择最合适的模型,(3) 需要跟踪工作流进度和模型使用情况,(4) 长时间任务卡住需要问题诊断和解决方案。
- 直接拷贝本地
vendor/目录到服务器——本地装了 dev 包,线上就跟着有,--no-dev根本没运行 - CI 脚本用了
composer update --no-dev替代install——lock 文件被改写,破坏部署可重现性 - 误以为
--optimize-autoloader能替代--no-dev——它只加速加载,phpunit照样在vendor/里躺着 -
COMPOSER_NO_DEV=0环境变量覆盖了命令行参数——CI 中需显式 unset 或设为1
require-dev 包被生产依赖间接引用怎么办
--no-dev 只跳过显式写在 require-dev 字段里的包,不管传递依赖。如果 A(生产包)→ B(生产包)→ C(dev-only 包),C 仍会被装进来。
这种情况无法靠 --no-dev 解决,得从依赖源头处理:
- 检查
composer why C定位谁拉进了 C - 用
composer prohibits C看是否能换掉带硬依赖的版本 - 必要时 fork B,移除对 C 的 require,并用
repositories指向私有源
别指望 config.platform 或 post-install-cmd rm -rf 来清理——前者对 require-dev 无效,后者会让 autoload 映射残留,运行时报错更隐蔽。










