composer create-project 仅消费模板而非导出项目,需手动构建含"type": "project"的模板包;未打正式tag时须加--stability=dev;预设逻辑依赖post-create-project-cmd脚本一次性执行。

create-project 命令本身不导出设置,它只消费模板
很多人误以为 composer create-project 能“导出当前项目为模板”,其实不是。这个命令是单向的:它从一个已存在的、带 composer.json 的包里拉取代码并初始化新项目。你无法用它反向生成模板。真要保存当前项目的结构和配置为可复用模板,必须手动准备一个符合规范的 Composer 包。
模板包的 composer.json 必须含 type: "project"
这是最关键的识别标识。如果漏掉或写成 "type": "library",create-project 会把它当普通依赖装进 vendor/,而不是复制整个骨架到目标目录。常见错误包括:
- 直接拷贝现有项目的
composer.json,但没改type字段 - 用了
require引入自己模板的包名,导致循环依赖 - 没删掉原项目的
vendor/和composer.lock—— 模板包里不该有这些
正确写法示例(精简):
{
"name": "myorg/starter",
"type": "project",
"description": "My team's base template",
"autoload": {
"psr-4": {"App\": "app/"}
}
}
版本不稳定时必须加 --stability=dev
如果你的模板包还没打正式 tag(比如只有 dev-main 分支),composer create-project myorg/starter 默认搜不到,报错 “Could not find package”。这不是路径或拼写问题,而是稳定性策略限制。
解决方法只有两个:
- 执行时加
--stability=dev:composer create-project myorg/starter myapp --stability=dev - 或者在模板包的
composer.json里加"minimum-stability": "dev"(不推荐,会影响下游使用)
另外,composer show myorg/starter 能查到 ≠ create-project 能用 —— 因为 show 默认查所有稳定性,而 create-project 默认只认 stable。
真正能“预设保存”的是 post-create-project-cmd 脚本
所谓“预设”,不是把配置固化在模板文件里,而是靠脚本在每次创建时动态注入。比如替换占位符、生成 .env、清空 Git 历史等。这些逻辑必须写在模板包根目录的 composer.json 的 scripts 字段中:
"scripts": {
"post-create-project-cmd": [
"sed -i 's/APP_NAME=MyApp/APP_NAME=${PROJECT_NAME}/g' .env",
"rm -rf .git"
]
}
注意:post-create-project-cmd 是钩子名,必须拼写准确;脚本内容不能依赖用户交互,否则在 CI 或加了 --no-interaction 时会失败。
最容易被忽略的是:这个脚本只在 create-project 过程中执行一次,之后再运行 composer install 不会触发它 —— 它不是通用生命周期钩子。











