create-project 本质是克隆远程仓库指定 commit 并执行 composer install 和 post-create-project-cmd 脚本,不解析占位符、不交互;模板包必须声明 "type": "project" 才能被识别,且钩子须置于模板根 composer.json 中,推荐使用 --remove-vcs --no-interaction --stability=stable 等参数确保稳定自动化。

create-project 本质是克隆,不是生成
它不解析 {{name}} 占位符、不提问、不渲染变量,只是把远程仓库某个 commit(通常是 main 分支或最新 tag)完整拷贝下来,再执行 composer install 和 post-create-project-cmd 脚本。所谓“脚手架效果”,完全依赖模板包作者预设的结构和钩子——你用的不是 Composer 的能力,而是别人写好的 composer.json 和脚本。
模板包必须声明 "type": "project"
这是 create-project 能识别它的唯一硬性条件。如果漏了这行,哪怕包名正确、仓库可访问,也会报 Could not find package。检查方式很简单:
composer show vendor/name | grep type
输出里必须含 project。常见错误包括:
- 把模板包设成
"type": "library"或干脆不写type字段 - 在模板自己的
composer.json里写了"require": { "vendor/name": "*" },造成循环依赖 - 用了私有 Git 仓库但没在全局或项目级
composer.json中配置repositories
post-create-project-cmd 必须写在模板的根 composer.json 里
这个钩子只在新生成的项目目录中执行,工作路径就是 myapp/,不是模板源码目录。很多人误把它写进某个依赖的 composer.json,结果脚本根本不跑。
正确写法示例(位于模板仓库根目录的 composer.json):
"scripts": {
"post-create-project-cmd": [
"echo 'Initializing new project...'",
"cp .env.example .env",
"php artisan key:generate"
]
}
注意点:
- 命令名大小写敏感,必须是
post-create-project-cmd,不能写成postCreateProjectCmd - 脚本里别用
../回溯到模板源码——它根本不存在于新项目中 - 如果调试时想跳过脚本,加
--no-scripts;想确认是否执行,加-vvv
创建命令不加参数,90% 会翻车
默认行为对自动化极不友好:不指定版本可能拉到 dev-main(不稳定),目录已存在直接报错,不删 .git 会导致首次 git push 把模板历史一起推上去。
推荐组合(Laravel 11 稳定版为例):
composer create-project laravel/laravel myapp "11.*" --remove-vcs --no-interaction --stability=stable
关键参数作用:
-
--remove-vcs:删掉模板自带的.git/目录,新项目干净起步 -
--no-interaction(简写-n):避免卡在 SSH 密码或“是否删除目录”提示上 -
--stability=stable:强制只认稳定版,防止意外拉到开发分支 - 版本字符串用双引号包裹(如
"11.*"),防 shell 解析出错
最容易被忽略的是:post-create-project-cmd 脚本执行时,composer.json 已被复制到新项目中,但 vendor/ 尚未安装完成——所以脚本里别直接 require vendor/autoload.php,除非你明确加了 --no-install 并手动处理。


















