installer-paths不是全局路径开关,仅对声明特定type(如wordpress-plugin)且已安装对应installer的包生效;全局改vendor目录只能用config.vendor-dir,且必须删除旧vendor后重装。

直接说结论:installer-paths 不是“改所有包路径”的开关,它只对声明了特定 type(如 wordpress-plugin)且已装对应 installer 的包生效;想全局挪 vendor,只能靠 config.vendor-dir,且必须删旧目录重装。
为什么 installer-paths 配了但包还在 vendor/ 下?
这不是配置写错了,而是三个关键条件没同时满足:
- 项目没运行
composer require composer/installers(或专用 installer,如wpackagist/installer)——没这个包,extra.installer-paths完全被忽略 - 目标包的
composer.json里"type"字段不匹配,比如你想定制monolog/monolog,但它声明的是"type": "library",而composer/installers默认不接管library - 已安装的包不会被重定位:删掉
vendor/和composer.lock后再跑composer install,否则规则只对新装/更新的包起作用
怎么让 WordPress 插件进 wp-content/plugins/?
这是最典型、也最容易踩坑的场景。核心是三方包自身得“配合”:
- 确认插件包(如
wpackagist-plugin/akismet)在 Packagist 上的type确实是wordpress-plugin(不是library或空) - 项目根目录执行:
composer require composer/installers - 在
composer.json的extra段加:{"installer-paths": {"wp-content/plugins/{$name}/": ["type:wordpress-plugin"]}}注意:{$name}是占位符,会被替换成包名最后一段(acme/my-plugin→my-plugin),路径必须以/结尾,且不能以/开头
想把私有包装进 resources/js/vendor 怎么办?
私有包通常没按生态规范设 type,得自己定义并映射:
- 在你自己的包的
composer.json中明确写:"type": "myapp-ui" - 确保项目已装
composer/installers - 在项目根目录
composer.json的extra段配:{"installer-paths": {"resources/js/vendor/{$name}/": ["type:myapp-ui"]}, "installer-types": {"myapp-ui": "library"}}installer-types不强制要求,但显式声明能避免某些 Composer 版本兼容问题;{$name}和{$vendor}可用,但别混用斜杠风格(如resources/js/vendor/{$name}/✅,resources\js\vendor\{$name}\❌)
config.vendor-dir 和 installer-paths 能一起用吗?
技术上可以,但逻辑上不该混用:
-
config.vendor-dir是全局搬家:所有包(包括composer/installers自身)都挪到新位置,影响autoload.php入口、bin/符号链接、IDE 索引路径 -
installer-paths是定向搬运:只对特定type的包生效,比如只动插件,不动monolog - 两者职责完全不同,强行叠加容易导致
require 'vendor/autoload.php'找不到入口、vendor/bin/phpunit命令失效等问题;真要改全局路径,就只用config.vendor-dir,并同步改bin-dir和所有硬编码引用
最常被忽略的一点是:installer-paths 规则一旦写错(比如路径以 / 开头、type 拼错、包没装 composer/installers),Composer 会静默跳过,不报错也不提示——所以排查时别只盯语法,重点看环境是否到位、包是否真的被识别为对应类型。











