create-vite
pnpm create vite 实际执行的是 npm 包 create-vite(与 vite 本体不同)。工程化背景见 工程化概览、工作原理。
下文从包管理器如何拉起脚手架,到 create-vite 内部流程做串联说明。
下文逻辑以 Vite 仓库中
packages/create-vite为准;具体实现会随版本迭代,以你本地安装的create-vite源码为准。
先分清两个概念:Vite 与 create-vite
- Vite:构建工具与开发服务器(
vite命令、vite.config等),负责开发与打包。 - create-vite:独立 npm 包,只做「把模板目录拷到目标文件夹、改
package.json、可选装依赖并启动 dev」等脚手架工作。
因此 pnpm create vite 实际执行的是 create-vite 这个包的入口,而不是直接调用 vite 本体。
pnpm create vite 是如何找到 create-vite 的?
各包管理器都约定:create <name> 会解析并执行名为 create-<name> 的包。
| 你输入的命令 | 实际拉起的包(概念上) |
|---|---|
pnpm create vite | create-vite |
npm create vite@latest | create-vite(可指定版本) |
yarn create vite | create-vite |
pnpm 会下载(或复用缓存)create-vite 到临时环境并执行其 bin,无需全局安装。这与「先 npm i -g create-vite 再执行」效果类似,但更干净。
源码入口与参数解析
create-vite 入口里用 mri 解析 process.argv(从第三个参数起,即用户传入部分),并配置了布尔选项与短参数别名。
// 与仓库中一致的思路:pnpm create vite -t vue-ts
import mri from "mri";
const argv = mri<{
template?: string;
help?: boolean;
overwrite?: boolean;
immediate?: boolean;
interactive?: boolean;
}>(process.argv.slice(2), {
boolean: ["help", "overwrite", "immediate", "interactive"],
alias: { h: "help", t: "template", i: "immediate" },
string: ["template"],
});
要点:
-t/--template:指定模板 id,例如vue-ts、react;合法值来自内置列表(见下文TEMPLATES)。-h/--help:打印帮助后退出。-i/--immediate:创建完成后直接安装依赖并启动 dev(与交互里「是否现在安装」对应)。--overwrite:目标目录非空时,等价于选择「清空后继续」。--interactive/--no-interactive:强制进入或退出交互;未指定时,一般用process.stdin.isTTY判断是否 TTY 交互环境。
注意:短参数
i对应的是immediate(立即安装并启动),不是interactive。
核心流程:init() 在做什么?
create-vite 的主体是异步函数 init(),可概括为下面几步(与源码顺序一致,略有合并说明)。
1. 帮助信息
若传入 help,打印 helpMessage(含用法、选项与当前版本可用模板列表)后 return。
2. 是否交互
const interactive = argInteractive ?? process.stdin.isTTY
非 TTY(如 CI、部分脚本环境)下往往走非交互分支:缺少信息时用默认值(例如默认目录名、默认模板等),具体以源码为准。
另外,源码里会通过 @vercel/detect-agent 的 determineAgent() 判断是否在「AI Agent」环境,并在交互模式下提示可用一条命令非交互创建的方式,便于自动化。
3. 解析项目目录
- 位置参数
argv._[0]可作为目标目录(会经formatTargetDir清洗非法字符等)。 - 未传且为交互模式时,用
@clack/prompts询问 Project name,再得到targetDir。 - 默认目录名在源码里为
vite-project(非交互且未指定时可能使用该默认)。
4. 目标目录已存在且非空
若目录存在且非空:
- 传了
--overwrite则直接清空(保留.git的策略见源码emptyDir)。 - 否则在交互模式下让用户选:取消 / 清空继续 / 忽略继续;非交互且未
overwrite则可能直接取消。
5. package.json 的 name 字段
packageName 通常取目标文件夹 basename;若不符合 npm 包名规则,会提示修正或自动 toValidPackageName。
6. 选择模板(框架 + 变体)
- 若已通过
-t传入模板,且该字符串在TEMPLATES列表中,则直接使用。 - 若传入的模板名不合法,交互模式下会提示重新选择;非交互则可能回退到默认模板(如
vanilla-ts,以源码为准)。
交互模式下通常是两步选择:
- Select a framework:Vue、React、Vanilla 等(
FRAMEWORKS配置驱动)。 - Select a variant:如
vue-ts/vue、react-ts/react等。
部分选项不是内置模板目录,而是 customCommand:选中后会拼好命令(把 TARGET_DIR 换成你的目录),spawn 执行另一条脚手架(例如 npm create vue@latest),然后 process.exit,不再走后面的「拷贝 template-*」逻辑。
7. React Compiler 变体
若模板名包含 react-compiler,会先置 isReactCompiler,并把模板名里的 -compiler 去掉以对应实际 template-* 目录;生成后再跑 setupReactCompiler 往项目里写入 Babel / 插件等相关依赖与配置(版本号以源码为准)。
8. 是否立即安装并启动
immediate 来自 -i / --immediate,或在交互里 confirm「Install with <pkgManager> and start now?」。
非交互且未指定时,一般为 false,只生成文件,最后打印 cd + install + dev 提示。
pkgManager 常从 npm_config_user_agent 解析(例如你在用 pnpm create 时倾向于用 pnpm 安装)。
9. 脚手架落盘:模板目录在哪?
内置模板路径大致为(相对 create-vite 包内入口文件):
../../template-${template}
例如 vue-ts → template-vue-ts 目录。随后:
readdir模板目录,先拷贝除package.json以外的文件;- 对
index.html会读模板内容并替换<title>...</title>为项目展示名; _gitignore等特殊文件名会通过renameFiles映射为.gitignore;- 最后读模板内
package.json,把name写成packageName,再写入目标目录。
10. 安装依赖与启动 dev
若 immediate 为真:
install:cross-spawn同步执行当前包管理器的 install 命令,cwd为目标项目根目录;测试环境可通过_VITE_TEST_CLI跳过真实安装。start:同理执行dev脚本。
否则用 prompts.outro 输出「接下来在项目里执行的三条命令」。
与文中示例代码的对应关系
你在文章里贴的 write / install / start 片段,正是上面落盘 + 可选安装启动部分的缩影。阅读源码时建议对照:
packages/create-vite/src/index.ts中的init、write、copy、install、start。
常用命令速查
# 交互创建(推荐本地尝鲜)
pnpm create vite
# 指定目录与模板,适合脚本 / CI
pnpm create vite my-app --template vue-ts
# 创建后立刻安装并启动
pnpm create vite my-app --template react-ts --immediate
# 非交互(无 TTY 或显式关闭交互时使用)
pnpm create vite my-app --template vanilla-ts --no-interactive
总结(一条线)
包管理器解析 create vite → 下载并执行 create-vite → mri 解析参数 →(TTY 则交互收集目录名、模板、是否立即安装)→ 校验模板 / 或转交 customCommand → 从 template-* 拷贝并改写 package.json 与 index.html → 按需 install + dev 或打印后续命令。
把这条链路记熟后,排查「为什么没进我想要的模板」「为什么 CI 里行为不一样」会直观很多:多半落在 TTY / --no-interactive、模板名是否合法、是否命中 customCommand 提前退出 这几类问题上。
参考文献
以下链接在编写时均可正常访问:
| 资料 | 说明 |
|---|---|
| create-vite 源码 | GitHub |
| Vite:创建项目 | 官方入门 |
相关文章
部署实践
Vite 项目的 CI/CD、多环境、CDN、Legacy 与体积预算等工程化要点。环境变量见 env;构建见 生产构建。
插件开发
Vite 插件兼容 Rollup 插件,并扩展 config、configureServer、transformIndexHtml 等钩子。原理见 工作原理。
进阶配置
Vite 进阶:server.proxy、resolve.alias、SSR、多页面、库模式、vite preview 等。环境变量见 env。
生产构建
vite build 使用 Rollup 打包并应用内置优化。开发阶段原理见 工作原理。
工作原理
Vite 是面向现代浏览器的前端构建工具:开发阶段利用原生 ES 模块与按需编译;生产构建由 Rollup 完成。对比见 Webpack 与 Vite、工程化概览。
其他配置
除 ESLint、Prettier 等规范文件外,仓库中常见的工具链与包管理配置如下。见 工程化概览。