必须用 composer install --no-dev,否则线上服务器一定会装进 phpunit、larastan 等 dev 包;它强制跳过 require-dev 解析与安装,但前提是 composer.lock 本身不含 packages-dev 记录,否则仍会报错或静默失效。

必须用 composer install --no-dev,否则线上服务器一定会装进 phpunit、larastan 这类包——不是“可能”,是默认就装。
为什么 composer install 默认装 dev 包?
它只认 composer.lock 文件里记了什么,不看 APP_ENV、不读 COMPOSER_DEV=0、也不管你是不是在 Docker 里跑。只要 lock 文件里有 "packages-dev" 区块(开发机生成的几乎都有),composer install 就会把它们全拉下来。
- 常见错误现象:
Class 'PHPUnit\Framework\TestCase' not found→ 实际是phpunit被装进去了但 autoload 没配对,说明它误入生产环境 -
vendor/bin/phpunit或vendor/bin/pint存在 → 这些本不该出现在线上服务器 -
--optimize-autoloader(即-o)完全不跳过任何包,只加速加载,phpunit照装不误
composer install --no-dev 到底做了什么?
它不是“尽量不装”,而是从解析阶段就绕开 require-dev:不下载、不解压、不写入 vendor/、不注册 autoload-dev 映射(比如 Tests\ 命名空间不会出现在 vendor/autoload_static.php 中)。
- 生效前提是
composer.lock里仍有packages-dev记录 ——--no-dev不会报错,也不会删 lock 文件内容 - 如果 lock 文件里已经混进了
phpunit/phpunit,说明上次composer update没加--no-dev,得先清理再重生成 -
--production和--no-dev完全等价,但--prod是无效参数,会报Unrecognized option "--prod"
Docker 和 CI/CD 里最容易漏掉的三件事
自动化流程一漏,镜像体积多出 20–50MB,启动变慢,还可能暴露调试入口。
- 别只写
RUN composer install --no-dev,要搭配RUN rm -rf vendor/ && composer install --no-dev --prefer-dist --optimize-autoloader --no-scripts,清缓存防复用 - CI 脚本中,
composer install前必须确认composer.lock是干净的:grep -q '"require-dev"' composer.lock && echo "lock is dirty" || echo "safe" - 多阶段构建时,
builder阶段命令必须含--no-dev,否则 copy 过来的还是带 dev 的 vendor
国内镜像源怎么配才真正起效?
镜像源只影响下载速度和成功率,不影响 --no-dev 的行为逻辑,但它能让 --no-dev 快速落地。
- 全局配置阿里云镜像:
composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/ - 验证是否生效:
composer config -g repo.packagist应输出上述 URL - 注意:宝塔面板常禁用
proc_open、putenv等函数,需在 PHP 管理中手动开启,否则composer install --no-dev会直接崩溃
最麻烦的不是命令本身,而是 lock 文件被污染后,--no-dev 看似执行成功,实际仍悄悄装进一堆 dev 工具——得靠 grep 检查 lock、靠 rm -rf vendor 清缓存、靠多阶段构建隔离风险。这些步骤漏掉任意一个,--no-dev 就形同虚设。











