私有扩展依赖装不上、更新慢、CI失败,九成因repositories顺序错误和未设"packagist.org": false;私有源须置数组首位,packagist.org需显式禁用,vcs URL须以.git结尾且可直clone,锁文件与autoload优化可大幅提升性能。

私有扩展依赖装不上、更新慢、CI 失败,九成问题出在 repositories 顺序和 "packagist.org": false 缺失——不是网络或权限问题,是 Composer 解析逻辑被默认行为劫持了。
私有源必须放在 repositories 数组最前面
Composer 查包是线性扫描 repositories 数组,命中即停,不回溯。一旦你把阿里云镜像或 Packagist 写在第一位,myorg/utils 这种私有包永远进不了认证环节,直接报 Could not find package。
- 正确写法:第一个元素必须是你的私有源,比如
{"type": "vcs", "url": "https://gitlab.internal/myorg/utils.git"}或{"type": "composer", "url": "https://repo.internal/"} - 错误写法:把私有源塞在第二位、第三位,甚至用对象形式声明(如
"repositories": { "internal": { ... } })——Composer 会静默忽略其余键,只读第一个 - 验证方式:运行
composer show myorg/utils --verbose,看dist.url是否指向你的私有地址,而不是packagist.org
packagist.org 必须显式禁用,且不能只靠 repositories 配置
只要项目级 composer.json 里写了 repositories 数组,Composer 就默认关闭隐式 packagist.org 源——但这个“关闭”不彻底:它仍会在所有自定义源失败后 fallback 到公网,导致超时或误装旧版。
- 必须在
composer.json根层级加这一行:"packagist.org": false,不能放错位置,也不能写成"packagist": false - 如果还要保留官方源作兜底(比如部分依赖仍在 Packagist),得手动加回来:
{"type": "composer", "url": "https://packagist.org", "packagist": false}——注意这是数组里的一项,不是顶层开关 - 别碰全局配置:
composer config -g packagist false会影响所有项目,CI 环境极易出错
vcs 类型 URL 必须满足三个硬条件,否则 clone 静默失败
用 "type": "vcs" 声明 Git 仓库时,Composer 不解析网页、不拼接 token、不走 auth.json,只认标准 git clone 地址。
- URL 必须以
.git结尾,例如https://gitlab.internal/myorg/utils.git;写成https://gitlab.internal/myorg/utils会报No valid composer.json was found - 不能是 HTML 页面地址(如 GitHub 的 Release 页面),Composer 不爬虫
- 不能带凭据(如
https://token@github.com/...),凭据必须走系统 SSH agent 或~/.ssh/config(HTTPS+PAT 方式则走auth.json) - 验证方法:在项目外手动执行
git clone https://gitlab.internal/myorg/utils.git,能通就大概率没问题
锁文件和 autoload 是性能瓶颈,不是网络
大型项目 composer install 卡在 Resolving dependencies,往往不是私有源慢,而是 composer.lock 膨胀、autoload 未优化导致 JSON 解析和类映射耗时飙升。
- 运行
composer update --lock(不带包名),清理composer.lock中已废弃的require-dev包残留,实测可让 12MB 锁文件降到 3MB,JSON 解析耗时下降 60%+ - 加
--optimize-autoloader把私有包 PSR-4 映射转成 classmap,但注意:若包内大量用class_exists("{$prefix}".$name)动态拼类名,classmap 会失效,得换--classmap-authoritative - 私有包自己的
composer.json里加"archive": {"exclude": ["/tests", "/docs", "/examples"]},避免 Satis 构建时为非生产路径生成哈希并写入 lock
最常被忽略的一点:Satis 或 Artifactory 的 packages.json 必须返回 200,且内容可解析——它挂了,Composer 不报错,只会默默 fallback 到 packagist.org,让你以为是配置问题。











