composer.json中vendor-dir无效,因该字段仅被全局/系统级config识别,项目级配置被忽略;唯一可靠方式是设COMPOSER_HOME并配其下config.json的vendor-dir。

不能靠项目级配置实现共享 vendor 目录,必须用全局 config + COMPOSER_HOME 组合生效。
为什么 composer.json 里写 "vendor-dir" 没用?
项目根目录下的 composer.json 不支持 vendor-dir 配置项——这个字段只在全局或系统级配置中被识别。你改了也没反应,composer install 依然照常往当前目录下建 vendor。
- Composer 的设计逻辑是:每个项目默认隔离依赖,
vendor-dir属于“环境策略”,不是“项目策略” - 即使你在
composer.json里加了"config": {"vendor-dir": "/shared/vendor"},运行时会被直接忽略 - 验证方式:执行
composer config vendor-dir,输出为空就说明没生效
COMPOSER_HOME + config.json 是唯一可靠路径
真正起作用的是 Composer 自身的配置加载链:先读 COMPOSER_HOME/config.json(全局),再读项目级 composer.json(覆盖部分非 vendor 相关配置)。要挪动 vendor,必须走这条链。
- 先设置环境变量:
export COMPOSER_HOME="/home/yourname/composer-global(Linux/macOS)或set COMPOSER_HOME=C:\users\you\composer-global(Windows) - 然后在该目录下创建
config.json,内容为:{"config": {"vendor-dir": "/opt/shared-vendor"}} - 注意路径权限:目标
vendor-dir必须对当前用户可写,且 PHP 进程能读取(比如 Web 请求时 require autoload.php) - 执行
composer global config vendor-dir可确认是否已注册成功
共享 vendor 带来的实际问题和限制
看似省空间,但会引入隐性耦合和版本冲突风险,不是所有场景都适合。
- 不同项目依赖同一包的不同主版本(如 A 用
monolog/monolog:^2.0,B 用^3.0),共享目录下只能存一个,必然崩 - 如果某个项目执行了
composer update,可能意外升级其他项目的依赖,尤其当没锁死composer.lock时 -
autoload.php路径写死在生成代码里,一旦vendor-dir改变,所有已生成的 autoloader 都得重刷——意味着每个项目仍需单独跑一次composer dump-autoload - 某些包含 bin 文件(如
phpunit),会统一装进vendor-bin,多个项目共用时命令行为不可预测
真正需要共享依赖的场景(如多租户 SaaS、Laravel 多应用共核),更稳妥的做法是固定依赖版本 + 构建时打包,而不是运行时共享 vendor 目录。全局 vendor-dir 是个技术上可行、但生产环境需谨慎评估的方案。











