合法type值为library、project、metapackage、composer-plugin及框架专用类型;自定义值需配installer才生效,否则被忽略或拒收。

composer.json 里的 type 字段到底有哪些合法值
官方明确支持的 type 值就那几个: library、project、metapackage、composer-plugin,以及若干框架专用类型(如 wordpress-plugin、cakephp-plugin)。你写个 "type": "my-own-thing" 不报错,但 Packagist 会拒收,Composer 也会当它不存在——默认按 library 处理。
-
library是默认值,不写也自动生效;适合提供类、工具函数、SDK 等可被require的代码包 -
project表示“这是个完整应用”,比如 Laravel 官方 starter,它不该被别人require进自己的项目里 -
metapackage必须空源码,只靠require拉依赖,连autoload都不能有,否则 Packagist 发布失败 -
composer-plugin要求包里实现Composer\Plugin\PluginInterface,且必须在extra.installer-types或插件自身声明中注册,否则 Composer 根本不加载它
为什么设成 project 后 composer require 就不灵了
不是不灵,是语义上就不该这么用。当你把一个包设为 "type": "project",Composer 会把它从“可被依赖的库”名单里剔除——这主要影响 Packagist 的索引逻辑和某些 IDE/CI 工具的识别,但更关键的是人脑认知:团队成员看到 type: project,就该明白“别去 require 它,要用就 create-project”。
- 运行
composer require vendor/my-app仍能成功安装,但会进vendor/目录,失去项目结构(比如public/、config/全乱套) - 真正起作用的是工具链:Laravel Installer、Drupal Console、Symfony CLI 都会扫描
type: project来决定是否允许作为模板 - 如果你自己开发一个应用模板并发布到 Packagist,却忘了写
"type": "project",用户用create-project初始化后可能缺失关键目录结构或脚本钩子
metapackage 看似简单,但一碰就报错的三个原因
很多人以为 metapackage 就是“删光 src/ 再改个 type”,结果上传 Packagist 直接失败,或者本地 composer install 报 Could not parse version constraint。
- 必须彻底清空
autoload、autoload-dev、bin字段——哪怕留一行注释,Packagist 都认为你在骗它“这包其实有代码” -
require里不能出现"self.version"或"dev-main"这类动态版本,所有版本号得是确定字符串(如"^8.2"),否则元包解析失败 - 不能有
repositories字段——元包只负责“声明依赖”,不负责“找依赖从哪来”,加了会被视为配置错误
自定义 type 值不是不行,但得配对 installer 才真有用
比如你想让自己的组件自动装进 packages/my-module/ 而不是 vendor/,光写 "type": "my-module" 没用。Composer 根本不知道怎么处理它,照样扔进 vendor/。
- 必须同时在
composer.json里声明:"extra": { "installer-types": ["my-module"] } - 还得在包里提供一个实现了
Composer\Installer\LibraryInstaller的类,并在autoload中正确映射 - 最终还要靠
composer/installers这个通用安装器,或你自己写的私有安装器来识别该type并接管路径逻辑 - 没配 installer 的自定义
type,等于贴了个标签没人认——既不报错,也不生效,纯属自我安慰
最常被忽略的一点:type 字段本身不改变 composer install 的执行流程,但它是一把钥匙——开的是 Packagist 的发布闸门、IDE 的依赖提示、部署脚本的分类逻辑,还有队友看到 composer.json 时的第一判断。写错不报错,但后续所有自动化环节都可能悄悄绕过你。


















