Composer require找不到虚拟包是因为默认不扫描私有源中的package类型仓库,必须在composer.json的repositories中显式声明"type": "package"且结构严格符合Schema。

为什么composer require找不到虚拟包
根本不是包名写错或网络不通,而是 Composer 默认不扫描私有源里的虚拟包(package 类型仓库),除非你显式把它声明为 repositories 数组中的一项,并且类型必须是 "package"——不能用 "composer" 或 "vcs" 代替。
常见错误包括:
- 把虚拟包元数据直接塞进 Satis/Artifactory 的
packages.json里,但没在项目composer.json的repositories中单独加一条{"type": "package", ...} - 误以为只要私有源启用了
composertype 就能自动发现虚拟包,其实它只索引真实发布的包(含name+version+dist或source) - 写了
"type": "package",但漏了"autoload"或"require"字段,导致 Composer 解析失败后静默跳过
package 类型仓库的 JSON 结构必须严格满足 Schema
Composer 对 package 类型的校验非常硬:字段缺失、嵌套错位、值类型不符,都会让整条仓库配置失效,且不报错。
最小可用结构示例(必须全部存在):
{
"type": "package",
"package": {
"name": "acme/internal-utils",
"version": "1.0.0",
"type": "library",
"autoload": {
"psr-4": {
"Acme\Internal\": "src/"
}
},
"dist": {
"type": "zip",
"url": "https://pkg.myorg.com/dist/internal-utils-1.0.0.zip",
"reference": "abc123"
}
}
}
关键点:
-
"package"是外层对象的键名,不是可选字段;里面再套一层完整包定义 -
"version"必须是字符串(如"1.0.0"),不能是1.0.0(数字类型) -
"dist"和"source"至少填一个;若用"dist","url"必须可公开访问或已配好auth.json - 如果包需要认证,
auth.json的 host 必须和dist.url的域名完全一致(比如pkg.myorg.com,不能带https://)
多个虚拟包怎么避免 name 冲突和覆盖
Composer 不会合并同名包,repositories 数组里靠前的 package 条目一旦匹配上 require 的包名,后面的就彻底忽略——哪怕版本号更高。
所以别把所有虚拟包塞进同一个 "package" 块里,而应拆成多条独立配置:
"repositories": [
{
"type": "package",
"package": { "name": "acme/utils", "version": "1.0.0", ... }
},
{
"type": "package",
"package": { "name": "acme/logger", "version": "2.1.0", ... }
}
]
注意:
- 顺序即优先级,高频更新的包建议放前面
- 不要用通配符或正则,
name必须精确匹配require中写的字符串 - 如果两个
package条目都声明了"acme/utils",只有第一个生效,第二个被丢弃,且无任何提示
验证是否真走虚拟包路径而不是 fallback 到 packagist.org
最可靠的方式是加 -vvv 并 grep 关键字,而不是看 vendor/ 是否出现文件——因为 fallback 成功也会生成目录。
执行:
composer -vvv require acme/utils 2>&1 | grep -E "(Loading|Downloading|GET)"
真正生效的表现是:
- 日志里出现
Loading package acme/utils(说明命中了package类型定义) - 接着出现
Downloading https://pkg.myorg.com/dist/...或Cloning from https://gitlab.com/...(取决于你填的是dist还是source) - 绝对没有
GET https://repo.packagist.org/p/acme/utils%24...json这类请求
如果看到后者,说明 "packagist.org": false 没加,或者它没放在 repositories 同级(不是数组内部),Composer 仍会先查官方源并 404 后才退到你的虚拟包定义——这种“兜底行为”会导致性能下降且掩盖配置问题。











