path仓库协作的核心问题是路径配置与安装行为缺乏统一约束:必须用相对路径、目录真实存在、require字段区分dev/生产、symlink由本地包控制、ci需预创建目录,否则静默失败。

团队协作中用 path 仓库本地开发依赖,最容易出问题的不是“怎么配”,而是“谁在什么时候装了什么、为什么CI跑不通、为什么别人拉代码后 vendor 里没模块”——核心矛盾在于路径配置和安装行为缺乏统一约束。
path 仓库必须写相对路径,且不能含环境变量占位符
虽然 Composer 支持在 repositories 中用 ${HOME} 或 $_ENV,但实际协作中这类写法会导致 composer install 在他人机器上直接失败(不报错,只是跳过该仓库),因为 Composer 解析 path 类型时只做简单字符串拼接,不执行环境变量展开。
- ✅ 正确写法:
"url": "modules/payment"(项目根目录下的相对路径) - ❌ 危险写法:
"url": "${HOME}/myproject/modules/payment"或"url": "../shared/payment" - 路径必须真实存在且含合法
composer.json;若目录不存在,composer install不报错也不警告,只是静默忽略该仓库
require 和 require-dev 的行为差异必须明确区分
path 仓库里的包如果只出现在 require-dev 字段,而你执行的是 composer install --no-dev(比如 CI 流程默认启用),那这个本地模块根本不会被安装——连软链或复制都不会发生,且无任何提示。
- 生产环境模块(如共享业务组件)必须放在
require,不能仅靠require-dev临时开发 - 若确需仅 dev 阶段使用(如本地调试工具包),应在 CI 脚本中显式加
--dev,并在 README 中注明 - 检查方式:运行
composer show看是否列出对应包名;若没出现,先确认是否被--no-dev过滤
symlink 开关必须由本地包自身控制,而非主项目
是否启用符号链接,取决于被引用的本地包(即 modules/payment/composer.json)是否声明了 "options": {"symlink": true}。主项目的 composer.json 无法覆盖这个设置。
- ✅ 本地包中写:
{"name":"myapp/payment","options":{"symlink":true}} - ❌ 主项目中加
"options"到repositories配置无效 - 启用 symlink 后,
vendor/myapp/payment是指向源目录的软链,修改源码立即生效;但composer update才会重新应用该选项,install不会变更已有链接 - Windows 用户需确保启用了开发者模式或以管理员身份运行终端,否则 symlink 创建失败且无提示
CI/CD 中 path 仓库必须确保路径存在且权限可读
CI 环境(如 GitHub Actions)默认没有 modules/ 目录,即使主项目 composer.json 里写了 path,也会因路径不存在而跳过——这常导致测试通过但线上行为异常。
- CI 脚本中必须显式创建并填充本地模块目录,例如:
mkdir -p modules/payment && cp -r ../internal-payment/* modules/payment/ - 不要依赖 Git submodules 自动拉取:submodule 路径与
path声明不一致时,Composer 仍会跳过 - 建议在
composer.json的scripts中加预检命令,例如:"pre-install-cmd": "test -d modules/payment || (echo 'ERROR: modules/payment missing' && exit 1)"
真正难的不是让 path 工作起来,而是让所有人对“这个本地包到底有没有被装进去”有确定性认知——它既不报错也不提示,又不进 composer.lock,全靠路径存在、字段位置、开关配置、CI 步骤四者严丝合缝。漏掉任意一环,协作就变成玄学调试。











