composer install --no-dev是生产部署硬性要求,它跳过require-dev包的安装与autoload-dev映射生成;若lock文件含dev记录、代码中误调用dev类或autoload配置不当,仍会导致class not found等运行时错误。

composer install --no-dev 是生产环境部署的硬性要求,不加它,phpunit、symfony/var-dumper、mockery/mockery 等包会直接进 vendor/,不是“可能出问题”,是必然导致体积膨胀、autoload 冲突、类加载失败甚至 Fatal error。
为什么 --no-dev 在 TP 项目里特别容易失效
ThinkPHP 默认不强制约束 require-dev 的使用边界,很多开发者把调试工具(如 topthink/think-trace)、测试辅助类、甚至部分命令行工具都塞进 require-dev,却在控制器或中间件里无条件调用 —— 这时 --no-dev 能删掉包,但删不掉代码里的 use 或 new,上线就报 Class not found。
-
composer.lock文件里如果还存着require-dev包的记录,composer install --no-dev就不会清理它们 —— 它只跳过安装,不回滚 lock - TP 的
app/helper.php或common.php里如果写了dump()或trace(),而对应类来自require-dev,那它就是运行时依赖,不是“开发专用” -
composer dump-autoload默认不加--no-dev,生成的vendor/autoload.php仍含autoload-dev映射,哪怕包没装,自动加载器也会尝试找路径,引发冲突或静默失败
TP 项目中 require-dev 包是否真能“只在开发用”
不能靠字段名判断,得看实际调用链。一个包只要被 src/ 或 app/ 下任何 PHP 文件直接引用,它就不该在 require-dev 里。
- 运行
composer depends topthink/think-trace --tree,确认没有app/controller/或app/middleware/路径出现在依赖树里 - 对每个
require-dev包执行:grep -r "think-trace" app/ src/ --include="*.php",结果非空就得挪到require -
topthink/think-swoole这类扩展,若线上也跑 Swoole 模式,就不能放require-dev;同理,topthink/think-queue若生产也在用队列,就必须进require
Docker 和 CI 里怎么写才不翻车
参数必须显式、不可省略、不能靠环境变量“默认生效”。COMPOSER_DEV_MODE=0 有作用,但 --no-dev 优先级更高,且更直白可控。
- Dockerfile 中必须写死:
RUN composer install --no-dev --optimize-autoloader,不能只写composer install再指望基础镜像设了变量 - GitHub Actions 缓存 key 必须带语义:
composer-${{ hashFiles('**/composer.lock') }}--no-dev,否则缓存复用会导致phpunit漏装或误装 - CI 流水线跑测试前要
composer install(不带--no-dev),测试通过后部署阶段必须切回composer install --no-dev --optimize-autoloader,两个阶段不能共用同一份vendor/
autoload-dev 和环境配置不是一回事
TP 项目里常有人把 config/dev/ 目录注册进 autoload-dev,以为“这样生产就不会加载 dev 配置”——这是错的。autoload-dev 只控制命名空间是否被写入自动加载器,不控制文件是否被 require。
- 真正加载配置的逻辑必须在
public/index.php或start.php里,用getenv('APP_ENV')或$_SERVER['APP_ENV']判断后手动require对应路径 - 别在
composer.json的autoload.files里写"config/{$_ENV['APP_ENV']}.php"—— Composer 不解析 PHP 变量,这行直接让composer dump-autoload报错 -
autoload-dev里注册的Tests\命名空间,只应在tests/目录下使用;如果某处业务代码写了new Tests\FooMock(),那就是硬编码错误,不是配置问题
composer.lock 提交到 Git 是底线,删 vendor、换 PHP 版本、重跑 install 都不如它可靠。所有环境差异,最终都得收敛到这个文件的一致性上 —— 否则你永远不知道线上跑的到底是哪套依赖。











