创建项目
-
新建文件夹 mycli_demo
-
在文件夹 mycli_demo 内新建文件 package.json
{ "name": "mycli_demo", "version": "1.0.0", "bin": { "mycli": "index.js" }, "author": "", "license": "ISC", "description": "", "dependencies": { "fs-extra": "^11.3.0", "prompts": "^2.4.2" } }
-
新建文件 templates\react\package.json
{ "name": "your-project-name", "version": "1.0.0", "description": "react + ts + vite 项目模板", "main": "index.js", "scripts": { "dev": "vite" }, "keywords": [], "author": "", "license": "ISC" }
-
新建文件 templates\vue\package.json
{ "name": "your-project-name", "version": "1.0.0", "description": "vue + ts + vite 项目模板", "main": "index.js", "scripts": { "dev": "vite" }, "keywords": [], "author": "", "license": "ISC" }
-
新建文件 index.js
#!/usr/bin/env node // prompts 用于与用户进行交互 const prompts = require("prompts"); // fs-extra 用于文件操作 const fse = require("fs-extra"); // path 用于处理文件路径 const path = require("path"); // 定义项目模板路径 const templateDir = path.join(__dirname, "templates"); // 定义交互问题 const questions = [ { type: "select", name: "projectType", message: "请选择项目类型:", choices: [ { title: "vue", value: "vue" }, { title: "react", value: "react" }, ], initial: 0, }, { type: "text", name: "projectName", message: "请输入项目名称:", validate: (value) => (value.trim() === "" ? "项目名称不能为空" : true), }, { type: "select", name: "packageManager", message: "请选择包管理器:", choices: [ { title: "npm", value: "npm" }, { title: "yarn", value: "yarn" }, ], initial: 0, }, ]; async function createProject() { try { // 发起交互,并获取用户输入 const answers = await prompts(questions); // 解析用户输入的项目信息 const { projectType, projectName, packageManager } = answers; // 根据用户输入的项目名称,生成新项目目录。 process.cwd() 用于获取当前工作目录的路径 const projectDir = path.join(process.cwd(), projectName); // 检查新项目目录是否已存在 if (fse.existsSync(projectDir)) { console.error(`项目目录 ${projectDir} 已存在,请选择其他名称。`); return; } // 创建项目目录 fse.ensureDirSync(projectDir); // 根据用户选择,获取目标模板路径 const templatePath = path.join(templateDir, projectType); // 复制模板目录到目标目录 fse.copySync(templatePath, projectDir); // 根据用户选择更新项目配置 const packageJsonPath = path.join(projectDir, "package.json"); // 读取 package.json 文件 const packageJson = fse.readJsonSync(packageJsonPath); // 更新 package.json 中的项目名称 packageJson.name = projectName; // 保存更新后的 package.json fse.writeJsonSync(packageJsonPath, packageJson, { spaces: 2 }); console.log(`项目 ${projectName} 创建成功!`); console.log(`请进入项目目录:cd ${projectName}`); console.log(`使用 ${packageManager} 安装依赖:${packageManager} install`); } catch (error) { if (error.name === "AbortError") { console.log("用户取消了项目创建。"); } else { console.error("创建项目时发生错误:", error); } } } // 执行创建项目函数 createProject();
安装依赖
pnpm i
或更新到最新版依赖
pnpm i prompts fs-extra
将本地包链接到全局
主要是为了方便本地调试包
npm link --force
此命令会强制将 mycli 链接到全局 node_modules 目录中,同时在全局 bin 目录中根据 package.json 中定义的 bin 字段创建对应的可执行文件
( --force 会强制覆盖已存在的 mycli 链接和可执行文件)
效果预览
命令行中输入 mycli 回车,便会开启交互,最终根据既定模板完成项目的创建。
{
"name": "reactDemo",
"version": "1.0.0",
"description": "react + ts + vite 项目模板",
"main": "index.js",
"scripts": {
"dev": "vite"
},
"keywords": [],
"author": "",
"license": "ISC"
}
更多交互命令
参考 prompts 官网 https://www.npmjs.com/package/prompts
脚手架开发的意义和原理
https://blog.csdn.net/weixin_41192489/article/details/125282893
脚手架的系统管理和发布
https://blog.csdn.net/weixin_41192489/article/details/125298121