composer install --no-dev 是跳过 dev 依赖的唯一推荐方式,它依据 composer.lock 安装生产依赖,忽略 require-dev;首次克隆无 lock 文件时则仅按 require 安装。

composer install 时跳过 dev 依赖的正确写法
直接用 --no-dev 参数就行,但必须配合 composer install,不是 composer update 或其他命令。它会读取 composer.lock 中记录的生产环境依赖列表,完全忽略 require-dev 里的包。
-
composer install --no-dev是唯一推荐方式;composer install --no-dev --optimize-autoloader更适合上线部署 - 如果项目还没生成
composer.lock(比如第一次克隆),--no-dev仍生效,但 composer 会按composer.json的require部分安装,不装require-dev - 误用
composer update --no-dev会导致composer.lock被重写,下次install仍可能拉错版本——除非你真要更新生产依赖
为什么 vendor/autoload.php 在 --no-dev 下仍能加载测试类
因为 autoloader 本身不区分 dev 或 prod,它只认 PSR-4/PSR-0 映射路径。只要某个包(比如 phpunit/phpunit)被装进 vendor/,它的类就可能被自动加载,哪怕你用了 --no-dev。
- 真正起作用的是「是否安装」:没装进去,自然加载不到;装了但没调用,也不影响运行
- 常见陷阱:CI 环境里执行
composer install --no-dev后,又手动运行vendor/bin/phpunit—— 这会失败,因为phpunit根本不在vendor/bin/里 - 检查是否生效:执行
ls vendor/ | grep phpunit,空输出才说明真的没装
CI/CD 部署脚本里怎么防手误
靠人记参数不可靠,得在流程里固化逻辑。关键是把 --no-dev 当成部署阶段的强制开关,而不是可选项。
- 在
.gitlab-ci.yml或GitHub Actions的 deploy job 里,明确写死composer install --no-dev --optimize-autoloader --no-interaction - 避免在部署机上残留
composer.json的require-dev字段误导自己:有些团队会维护两份composer.json(prod/composer.json + dev/composer.json),没必要,徒增同步成本 - 如果用了
COMPOSER_NO_DEV=1环境变量,它等价于--no-dev,但优先级低于命令行参数,且容易被忽略——不如直接写清楚
require-dev 里的包意外进入生产环境的典型场景
不是 --no-dev 失效,而是某些操作绕过了它。最常发生在本地开发后直接打包整个 vendor/ 上线。
- 用
rsync -av ./vendor/ user@prod:/app/vendor/同步时,根本没走 composer 流程,dev 包全在里面 -
composer dump-autoload --optimize不影响依赖安装,但它会让所有已安装类(包括 dev 包)的加载更快——别把它和--no-dev混为一谈 - 某些私有包在
require-dev里写了"my/package": "dev-main",结果因分支名含dev-被误认为是开发专用——其实只是命名习惯,composer 不解析这个前缀










