本地插件(type: "path")与远程仓库走完全不同的解析路径,path类型跳过远程元数据抓取和版本约束解析,仅读取本地composer.json的name和version字段;require时必须用"*"或"dev-main"等开发标识,不可用"^1.2.0"等语义化版本,否则静默失败。

本地插件(type: "path")和远程仓库(type: "vcs" 或默认 Packagist)在 Composer 中走的是完全不同的解析路径,不兼容不是“版本没对上”,而是根本没进同一套逻辑——path 类型跳过所有远程元数据抓取、版本约束解析、provider 匹配,只读本地 composer.json 的 name 和 version 字段。一旦你发现本地改了代码但运行时没生效,或 composer show 输出和预期不符,问题几乎一定出在这层机制差异上。
为什么 composer require vendor/name:1.2.3 会静默失败
Composer 看到带具体版本号的写法,会强制走远程包查找流程:1.2.3 被当作语义化版本去查 packages.json,而 path 仓库根本不提供这个能力。它只响应 *、dev-main、@dev 这类开发标识。
-
composer require vendor/name:*✅ 触发 path 映射,读取本地composer.json的version -
composer require vendor/name:dev-main✅ 前提是本地包composer.json里有"version": "dev-main"或分支名匹配 -
composer require vendor/name:^1.2.0❌ 即使本地version是1.2.5,也会报Could not find package - 如果
minimum-stability是stable,连dev-main都会被跳过,必须加--stability=dev或临时设"minimum-stability": "dev"
repositories 配置位置错误导致本地插件被完全忽略
Composer 只读项目根目录下 composer.json 最外层的 repositories 字段。写错位置等于没写。
- ❌ 写在
"extra": { "repositories": [...] }→ 被忽略 - ❌ 写在子目录的
composer.json里 → 不加载 - ✅ 必须和
require、autoload同级,且在顶层 JSON 对象中 - ⚠️ 如果你同时用了私有镜像,必须把
path条目放在repositories数组首位,并加{"packagist.org": false},否则 Composer 仍优先查远程
怎么确认 Composer 真正在用本地路径而不是远程包
不能只信 composer show 的输出,它可能显示 source: path ../my-pkg 但实际加载的仍是 vendor 里的旧副本——因为 composer.lock 里还存着旧的 dist URL。
- 删掉
vendor/vendor/name目录,再跑composer update vendor/name --with-dependencies -v,看日志里有没有Found package vendor/name at path ../my-pkg - 检查
vendor/vendor/name是否为符号链接(Linux/macOS)或 junction(Windows);如果是普通文件夹,说明没走 path - 改本地包源码,在关键函数里加
echo "LOCAL HIT"; die;,直接运行项目脚本验证输出 - 运行
composer diagnose,它会提示repositories是否可读、路径是否存在
最常被忽略的一点:切换回远程依赖后,光删 repositories 条目不够,composer.lock 里仍硬编码着 "type": "path" 的记录,必须执行 composer update vendor/name --with-dependencies 才能刷新 lock 文件中的 source 类型。否则下次 install 依然 symlink。











