生产部署必须使用 composer install --no-dev,否则会安装 phpunit 等开发依赖,引入安全风险、增大镜像体积(30–200MB)、拖慢 autoload 生成,并可能因 dev 包污染自动加载导致类冲突或意外初始化。

为什么 composer install --no-dev 必须出现在生产部署中
不加 --no-dev 会导致生产环境安装开发依赖,比如 phpunit/phpunit、friendsofphp/php-cs-fixer、laravel/pint 等——这些包既不参与运行时逻辑,又可能引入安全风险、增大部署体积、拖慢 autoload 生成速度。
更隐蔽的问题是:某些 dev 包的自动加载规则会污染 vendor/autoload.php,导致类名冲突或意外触发初始化逻辑(例如某测试工具在加载时执行了文件系统扫描)。
- 生产镜像体积常因此增加 30–200MB(取决于项目依赖树深度)
-
composer dump-autoload -o在含 dev 包时可能失败或生成低效的 classmap - 部分 CI/CD 流水线未清理
composer.lock中的require-dev字段,导致误判依赖范围
composer install --no-dev 和 composer install --optimize-autoloader 的关系
两者不互斥,但顺序和组合影响结果。单独用 --no-dev 不会自动启用优化;必须显式加 --optimize-autoloader(或简写 -o)才能生成扁平 classmap、跳过 PSR-4 动态查找。
典型安全写法是:
composer install --no-dev --optimize-autoloader --no-interaction
-
--no-interaction防止因缺少交互输入(如 GitHub token 提示)导致流水线卡住 - 若项目含大量 PSR-4 命名空间,
-o可提升类加载性能 15–40% - 注意:
-o会忽略autoload-dev中的路径,所以它天然兼容--no-dev
CI/CD 中容易漏掉的三个关键点
很多团队只在最后一步跑 composer install --no-dev,却忽略了前置条件是否干净。
- 没清空
vendor/或没删composer.lock就重装 → 可能残留旧 dev 包 - CI 使用的 PHP 版本高于生产环境 → 某些
dev包的platform配置被绕过,导致本地能装、线上报错Your requirements could not be resolved - 误用
composer update --no-dev替代install→ 会改写composer.lock,破坏可重现性
验证是否真正生效的快速检查法
别只信日志里有没有 “Installing dependencies from lock file”,要看实际结果。
- 执行
ls vendor/ | grep -E '^(phpunit|php-cs-fixer|pestphp|laravel/pint)' | wc -l,输出应为0 - 检查
vendor/composer/autoload_classmap.php头部注释是否含Generated by Composer且无dev相关路径 - 运行
composer show --dev,应报错There are no packages required in the require-dev section
最麻烦的情况是:某些包把开发工具塞进 require 而非 require-dev(比如旧版 monolog/monolog 的某些分支),这时光靠 --no-dev 拦不住,得人工审计 composer.json。










