create-admin-mvp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +175 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +159 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +41 -0
- package/templates/admin-portal/ .stylelintrc.cjs +39 -0
- package/templates/admin-portal/.dockerignore +60 -0
- package/templates/admin-portal/.env +29 -0
- package/templates/admin-portal/.env.development +41 -0
- package/templates/admin-portal/.env.example +4 -0
- package/templates/admin-portal/.env.production +41 -0
- package/templates/admin-portal/.eslintrc.cjs +45 -0
- package/templates/admin-portal/.github/workflows/ci.yml +217 -0
- package/templates/admin-portal/.husky/commit-msg +11 -0
- package/templates/admin-portal/.husky/pre-commit +10 -0
- package/templates/admin-portal/.lintstagedrc.json +13 -0
- package/templates/admin-portal/.prettierrc.cjs +19 -0
- package/templates/admin-portal/.stylelintrc.cjs +35 -0
- package/templates/admin-portal/Dockerfile +35 -0
- package/templates/admin-portal/README.md +196 -0
- package/templates/admin-portal/commitlint.config.cjs +41 -0
- package/templates/admin-portal/docker-compose.yml +35 -0
- package/templates/admin-portal/index.html +13 -0
- package/templates/admin-portal/nginx.conf +45 -0
- package/templates/admin-portal/package-lock.json +10730 -0
- package/templates/admin-portal/package.json +62 -0
- package/templates/admin-portal/playwright-report/index.html +85 -0
- package/templates/admin-portal/playwright.config.ts +73 -0
- package/templates/admin-portal/pnpm-lock.yaml +1620 -0
- package/templates/admin-portal/postcss.config.cjs +56 -0
- package/templates/admin-portal/public/vite.svg +1 -0
- package/templates/admin-portal/src/App.vue +15 -0
- package/templates/admin-portal/src/assets/styles/main.css +36 -0
- package/templates/admin-portal/src/assets/vue.svg +1 -0
- package/templates/admin-portal/src/components/HelloWorld.vue +41 -0
- package/templates/admin-portal/src/layout/index.vue +23 -0
- package/templates/admin-portal/src/main.ts +12 -0
- package/templates/admin-portal/src/mock/auth.ts +26 -0
- package/templates/admin-portal/src/permission.ts +15 -0
- package/templates/admin-portal/src/router/index.ts +21 -0
- package/templates/admin-portal/src/style.css +79 -0
- package/templates/admin-portal/src/views/About.vue +15 -0
- package/templates/admin-portal/src/views/Home.vue +15 -0
- package/templates/admin-portal/src/views/login/index.vue +34 -0
- package/templates/admin-portal/test-results/.last-run.json +23 -0
- package/templates/admin-portal/test-results/results.json +882 -0
- package/templates/admin-portal/tests/e2e/example.spec.ts +52 -0
- package/templates/admin-portal/tests/unit/example.test.ts +49 -0
- package/templates/admin-portal/tsconfig.app.json +18 -0
- package/templates/admin-portal/tsconfig.json +7 -0
- package/templates/admin-portal/tsconfig.node.json +22 -0
- package/templates/admin-portal/vite.config.ts +21 -0
- package/templates/admin-portal/vitest.config.ts +49 -0
- package/templates/admin-portal/vitest.setup.ts +60 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
18
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
19
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
20
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
21
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
22
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
23
|
+
mod
|
|
24
|
+
));
|
|
25
|
+
|
|
26
|
+
// src/index.ts
|
|
27
|
+
var import_commander = require("commander");
|
|
28
|
+
var import_chalk2 = __toESM(require("chalk"));
|
|
29
|
+
|
|
30
|
+
// src/prompts.ts
|
|
31
|
+
var import_inquirer = __toESM(require("inquirer"));
|
|
32
|
+
async function askScaffoldQuestions() {
|
|
33
|
+
const answers = await import_inquirer.default.prompt([
|
|
34
|
+
{
|
|
35
|
+
name: "projectName",
|
|
36
|
+
message: "\u9879\u76EE\u540D\u79F0\uFF1A",
|
|
37
|
+
type: "input",
|
|
38
|
+
validate: (input) => input.trim() ? true : "\u8BF7\u8F93\u5165\u9879\u76EE\u540D\u79F0"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: "description",
|
|
42
|
+
message: "\u9879\u76EE\u63CF\u8FF0\uFF1A",
|
|
43
|
+
type: "input",
|
|
44
|
+
default: "Admin & Big-screen scaffold project"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: "templates",
|
|
48
|
+
message: "\u8BF7\u9009\u62E9\u9700\u8981\u7684\u6A21\u677F\uFF1A",
|
|
49
|
+
type: "checkbox",
|
|
50
|
+
choices: [
|
|
51
|
+
{ name: "\u540E\u53F0\u7BA1\u7406\uFF08admin-portal\uFF09", value: "admin-portal", checked: true },
|
|
52
|
+
{ name: "\u6570\u636E\u5927\u5C4F\uFF08dashboard-bigscreen\uFF09", value: "dashboard-bigscreen" },
|
|
53
|
+
{ name: "Mock \u670D\u52A1\uFF08mock-service\uFF09", value: "mock-service" }
|
|
54
|
+
],
|
|
55
|
+
validate: (list) => list.length ? true : "\u81F3\u5C11\u9009\u62E9\u4E00\u4E2A\u6A21\u677F"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: "enableMock",
|
|
59
|
+
message: "\u662F\u5426\u542F\u7528\u5185\u7F6E Mock\uFF1F",
|
|
60
|
+
type: "confirm",
|
|
61
|
+
default: true
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: "enableAI",
|
|
65
|
+
message: "\u662F\u5426\u52A0\u5165 AI \u6A21\u5757\uFF1F",
|
|
66
|
+
type: "confirm",
|
|
67
|
+
default: false
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: "enableDeploy",
|
|
71
|
+
message: "\u662F\u5426\u751F\u6210\u90E8\u7F72\u811A\u672C\uFF08Docker/CI\uFF09\uFF1F",
|
|
72
|
+
type: "confirm",
|
|
73
|
+
default: true
|
|
74
|
+
}
|
|
75
|
+
]);
|
|
76
|
+
return answers;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// src/utils.ts
|
|
80
|
+
var import_fs_extra = __toESM(require("fs-extra"));
|
|
81
|
+
var import_path = __toESM(require("path"));
|
|
82
|
+
var import_chalk = __toESM(require("chalk"));
|
|
83
|
+
async function copyTemplate(templateDir, targetDir, variables) {
|
|
84
|
+
const files = await import_fs_extra.default.readdir(templateDir);
|
|
85
|
+
for (const file of files) {
|
|
86
|
+
const srcPath = import_path.default.join(templateDir, file);
|
|
87
|
+
const destPath = import_path.default.join(targetDir, file);
|
|
88
|
+
const stat = await import_fs_extra.default.stat(srcPath);
|
|
89
|
+
if (stat.isDirectory()) {
|
|
90
|
+
await import_fs_extra.default.ensureDir(destPath);
|
|
91
|
+
await copyTemplate(srcPath, destPath, variables);
|
|
92
|
+
} else {
|
|
93
|
+
let content = await import_fs_extra.default.readFile(srcPath, "utf-8");
|
|
94
|
+
content = replaceVariables(content, variables);
|
|
95
|
+
await import_fs_extra.default.writeFile(destPath, content);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function replaceVariables(content, variables) {
|
|
100
|
+
let result = content;
|
|
101
|
+
for (const [key, value] of Object.entries(variables)) {
|
|
102
|
+
const regex = new RegExp(`\\{\\{${key}\\}\\}`, "g");
|
|
103
|
+
result = result.replace(regex, value);
|
|
104
|
+
}
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
async function installDependencies(targetDir, packageManager = "pnpm") {
|
|
108
|
+
const { execSync } = await import("child_process");
|
|
109
|
+
console.log(import_chalk.default.cyan(`
|
|
110
|
+
\u6B63\u5728\u4F7F\u7528 ${packageManager} \u5B89\u88C5\u4F9D\u8D56...`));
|
|
111
|
+
try {
|
|
112
|
+
execSync(`${packageManager} install`, { cwd: targetDir, stdio: "inherit" });
|
|
113
|
+
console.log(import_chalk.default.green("\u2713 \u4F9D\u8D56\u5B89\u88C5\u5B8C\u6210"));
|
|
114
|
+
} catch (error) {
|
|
115
|
+
console.log(import_chalk.default.yellow("\u4F9D\u8D56\u5B89\u88C5\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u5B89\u88C5"));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async function initGit(targetDir) {
|
|
119
|
+
const { execSync } = await import("child_process");
|
|
120
|
+
try {
|
|
121
|
+
execSync("git init", { cwd: targetDir, stdio: "inherit" });
|
|
122
|
+
console.log(import_chalk.default.green("\u2713 Git \u4ED3\u5E93\u521D\u59CB\u5316\u5B8C\u6210"));
|
|
123
|
+
} catch (error) {
|
|
124
|
+
console.log(import_chalk.default.yellow("Git \u521D\u59CB\u5316\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u521D\u59CB\u5316"));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// src/index.ts
|
|
129
|
+
var import_path2 = __toESM(require("path"));
|
|
130
|
+
var import_fs_extra2 = __toESM(require("fs-extra"));
|
|
131
|
+
var program = new import_commander.Command();
|
|
132
|
+
program.name("create-mvp").description("Admin & Big-screen project scaffold").version("0.1.0").action(async () => {
|
|
133
|
+
try {
|
|
134
|
+
console.log(import_chalk2.default.cyan("\n\u6B22\u8FCE\u4F7F\u7528 create-mvp \u811A\u624B\u67B6\uFF01\n"));
|
|
135
|
+
const answers = await askScaffoldQuestions();
|
|
136
|
+
const targetDir = import_path2.default.join(process.cwd(), answers.projectName);
|
|
137
|
+
if (await import_fs_extra2.default.pathExists(targetDir)) {
|
|
138
|
+
console.log(import_chalk2.default.red(`
|
|
139
|
+
\u76EE\u5F55 ${answers.projectName} \u5DF2\u5B58\u5728\uFF01`));
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
console.log(import_chalk2.default.cyan(`
|
|
143
|
+
\u6B63\u5728\u521B\u5EFA\u9879\u76EE ${answers.projectName}...`));
|
|
144
|
+
for (const template of answers.templates) {
|
|
145
|
+
const templateDir = import_path2.default.join(__dirname, "../templates", template);
|
|
146
|
+
await copyTemplate(templateDir, targetDir, {
|
|
147
|
+
projectName: answers.projectName,
|
|
148
|
+
description: answers.description
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
console.log(import_chalk2.default.green("\u2713 \u9879\u76EE\u521B\u5EFA\u5B8C\u6210"));
|
|
152
|
+
await initGit(targetDir);
|
|
153
|
+
await installDependencies(targetDir);
|
|
154
|
+
console.log(import_chalk2.default.cyan("\n\u9879\u76EE\u521B\u5EFA\u6210\u529F\uFF01"));
|
|
155
|
+
console.log(import_chalk2.default.yellow(`
|
|
156
|
+
\u8BF7\u8FDB\u5165\u9879\u76EE\u76EE\u5F55\uFF1A`));
|
|
157
|
+
console.log(import_chalk2.default.white(` cd ${answers.projectName}`));
|
|
158
|
+
console.log(import_chalk2.default.yellow(`
|
|
159
|
+
\u542F\u52A8\u5F00\u53D1\u670D\u52A1\u5668\uFF1A`));
|
|
160
|
+
console.log(import_chalk2.default.white(` npm run dev`));
|
|
161
|
+
console.log(import_chalk2.default.yellow(`
|
|
162
|
+
\u6784\u5EFA\u9879\u76EE\uFF1A`));
|
|
163
|
+
console.log(import_chalk2.default.white(` npm run build`));
|
|
164
|
+
console.log(import_chalk2.default.yellow(`
|
|
165
|
+
\u8FD0\u884C\u6D4B\u8BD5\uFF1A`));
|
|
166
|
+
console.log(import_chalk2.default.white(` npm run test:unit`));
|
|
167
|
+
console.log(import_chalk2.default.white(` npm run test:e2e`));
|
|
168
|
+
console.log(import_chalk2.default.cyan("\n\u795D\u4F60\u5F00\u53D1\u6109\u5FEB\uFF01\n"));
|
|
169
|
+
} catch (error) {
|
|
170
|
+
console.log(import_chalk2.default.red("\n\u9879\u76EE\u521B\u5EFA\u5931\u8D25\uFF1A"), error);
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
program.parse();
|
|
175
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/prompts.ts","../src/utils.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from 'commander'\nimport chalk from 'chalk'\nimport { askScaffoldQuestions } from './prompts'\nimport { copyTemplate, installDependencies, initGit } from './utils'\nimport path from 'path'\nimport fs from 'fs-extra'\n\nconst program = new Command()\n\nprogram\n .name('create-mvp')\n .description('Admin & Big-screen project scaffold')\n .version('0.1.0')\n .action(async () => {\n try {\n console.log(chalk.cyan('\\n欢迎使用 create-mvp 脚手架!\\n'))\n\n const answers = await askScaffoldQuestions()\n\n const targetDir = path.join(process.cwd(), answers.projectName)\n\n if (await fs.pathExists(targetDir)) {\n console.log(chalk.red(`\\n目录 ${answers.projectName} 已存在!`))\n return\n }\n\n console.log(chalk.cyan(`\\n正在创建项目 ${answers.projectName}...`))\n\n for (const template of answers.templates) {\n const templateDir = path.join(__dirname, '../templates', template)\n await copyTemplate(templateDir, targetDir, {\n projectName: answers.projectName,\n description: answers.description,\n })\n }\n\n console.log(chalk.green('✓ 项目创建完成'))\n\n await initGit(targetDir)\n\n await installDependencies(targetDir)\n\n console.log(chalk.cyan('\\n项目创建成功!'))\n console.log(chalk.yellow(`\\n请进入项目目录:`))\n console.log(chalk.white(` cd ${answers.projectName}`))\n console.log(chalk.yellow(`\\n启动开发服务器:`))\n console.log(chalk.white(` npm run dev`))\n console.log(chalk.yellow(`\\n构建项目:`))\n console.log(chalk.white(` npm run build`))\n console.log(chalk.yellow(`\\n运行测试:`))\n console.log(chalk.white(` npm run test:unit`))\n console.log(chalk.white(` npm run test:e2e`))\n console.log(chalk.cyan('\\n祝你开发愉快!\\n'))\n } catch (error) {\n console.log(chalk.red('\\n项目创建失败:'), error)\n process.exit(1)\n }\n })\n\nprogram.parse()\n","/*\n * @Author: xhp 837792102@qq.com\n * @Date: 2026-01-23 14:44:30\n * @LastEditors: xhp 837792102@qq.com\n * @LastEditTime: 2026-01-23 16:39:21\n * @FilePath: /admin-mvp/packages/cli/src/prompts.ts\n * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE\n */\n// 导入 inquirer 模块,用于交互式命令行提示\nimport inquirer from 'inquirer'\n\n// 定义 ScaffoldAnswers 类型,用于存储脚手架问题的答案\nexport type ScaffoldAnswers = {\n \n // 项目名称:用户输入的项目名称字符串\n projectName: string\n \n // 项目描述:用户输入的项目描述信息\n description: string\n \n // 模板选择:用户选择的模板数组,可能包含 'admin-portal'、'dashboard-bigscreen'、'mock-service' 等\n templates: string[]\n \n // 是否启用 Mock:布尔值,表示是否启用内置的 Mock 服务\n enableMock: boolean\n \n // 是否启用 AI:布尔值,表示是否加入 AI 模块功能\n enableAI: boolean\n \n // 是否生成部署脚本:布尔值,表示是否生成 Docker/CI 相关的部署配置文件\n enableDeploy: boolean\n}\n\n\nexport async function askScaffoldQuestions(): Promise<ScaffoldAnswers> {\n const answers = await inquirer.prompt([\n {\n name: 'projectName',\n message: '项目名称:',\n type: 'input',\n validate: (input: string) => (input.trim() ? true : '请输入项目名称'),\n },\n {\n name: 'description',\n message: '项目描述:',\n type: 'input',\n default: 'Admin & Big-screen scaffold project',\n },\n {\n name: 'templates',\n message: '请选择需要的模板:',\n type: 'checkbox',\n choices: [\n { name: '后台管理(admin-portal)', value: 'admin-portal', checked: true },\n { name: '数据大屏(dashboard-bigscreen)', value: 'dashboard-bigscreen' },\n { name: 'Mock 服务(mock-service)', value: 'mock-service' },\n ],\n validate: (list: string[]) => (list.length ? true : '至少选择一个模板'),\n },\n {\n name: 'enableMock',\n message: '是否启用内置 Mock?',\n type: 'confirm',\n default: true,\n },\n {\n name: 'enableAI',\n message: '是否加入 AI 模块?',\n type: 'confirm',\n default: false,\n },\n {\n name: 'enableDeploy',\n message: '是否生成部署脚本(Docker/CI)?',\n type: 'confirm',\n default: true,\n },\n ])\n\n return answers as ScaffoldAnswers\n}","// 引入第三方库:fs-extra 是对 Node 原生 fs 的增强,path 用于路径拼接,chalk 用于终端彩色输出\n// 这行代码导入了一个叫 fs-extra 的库,它扩展了 Node.js 内置的 fs (文件系统)模块,提供了更多实用的文件操作功能。\nimport fs from 'fs-extra'\n//这行代码导入 Node.js 内置的 path 模块,用来处理文件和目录路径。\nimport path from 'path'\n//这行代码导入 chalk 库,可以在终端输出彩色的文字,让信息更清晰。\nimport chalk from 'chalk'\n\n/**\n * 递归地把模板目录 templateDir 中的所有文件/文件夹复制到目标目录 targetDir,\n * 并在复制文件内容时根据 variables 做变量替换({{变量名}} → 实际值)。\n */\n\n//这行定义了一个异步函数 copyTemplate ,并将其导出供其他文件使用。 async 表示这是一个异步函数。\nexport async function copyTemplate(\n //这是函数的第一个参数 templateDir ,类型是字符串,表示模板目录的路径。\n templateDir: string, // 模板目录绝对路径\n //这是函数的第二个参数 targetDir ,类型是字符串,表示目标目录的路径。\n targetDir: string, \n //这是函数的第三个参数 variables ,是一个键值都是字符串的对象,用来存储要替换的变量。 // 目标目录绝对路径\n variables: Record<string, string> // 变量键值对,如 { projectName: 'my-app' }\n) {\n // 读取模板目录下的所有文件/文件夹名\n //这行读取模板目录下的所有文件和子目录名,存到 files 变量中。 await 表示等待异步操作完成。\n \n // readdir 返回的是 string[],即模板目录下所有文件/文件夹的名字数组\n // readdir 返回的是一个 string[] 类型的数组,例如:\n // 假设 templateDir 目录下有以下文件和子目录:\n // - package.json\n // - src/\n // - .gitignore\n // 那么 files 的值就是:\n // ['package.json', 'src', '.gitignore']\n const files: string[] = await fs.readdir(templateDir) // readdir 返回 Promise<string[]>,必须用 await 等待异步结果,才能继续后续同步遍历\n\n // 逐个处理\n for (const file of files) {\n // `files` 里只是“文件名/子目录名”,并不包含父路径;\n // 为了拿到完整路径去读取或递归,必须把 templateDir 拼回去。\n // 举例:假设 templateDir = '/tmp/template',file = 'src/App.vue'\n // 那么 path.join(templateDir, file) 会返回 '/tmp/template/src/App.vue'\n\n // 递归调用时,上一层把 templateDir 已经拼到了“当前层级”目录,\n // 因此这一层只需把 file(当前层级的子文件/子目录名)再拼上去,\n // 就能拿到从最初模板根目录开始的完整路径。\n // 举例:\n // 第1层:templateDir = /tmp/template\n // file = src\n // → srcPath = /tmp/template/src\n // 第2层:templateDir = /tmp/template/src (上一层递归传进来的)\n // file = App.vue\n // → srcPath = /tmp/template/src/App.vue\n const srcPath = path.join(templateDir, file) // path.join 只是纯字符串拼接,同步立即返回,无需 await\n const destPath = path.join(targetDir, file) // 同上,同步操作\n const stat = await fs.stat(srcPath) // fs.stat 需要访问磁盘,是异步 I/O,必须 await 等待结果\n\n if (stat.isDirectory()) {\n // 如果是目录:先确保目标目录存在,再递归复制\n await fs.ensureDir(destPath)\n await copyTemplate(srcPath, destPath, variables)\n } else {\n // 如果是文件:读取内容 → 替换变量 → 写入目标路径\n let content = await fs.readFile(srcPath, 'utf-8')\n // replaceVariables 是一个自定义工具函数,作用是把文件内容里出现的 {{变量名}} 占位符\n // 全部替换成用户传入的对应值。举例:content 里有 \"{{projectName}}\",variables 里给出\n // { projectName: 'my-app' },执行后这段文本会变成 \"my-app\"。\n // 因为 replaceVariables 返回的是替换后的全新字符串,必须重新赋值给 content,\n // 否则后续 writeFile 写入的还是原来的旧内容,变量替换就白做了。\n content = replaceVariables(content, variables)\n await fs.writeFile(destPath, content)\n }\n }\n}\n\n/**\n * 将文本中出现的 {{key}} 全部替换为对应的 value。\n * 支持全局替换(一行里出现多次也能全部替换)。\n */\nfunction replaceVariables(content: string, variables: Record<string, string>): string {\n // 用 result 变量保存一份原始内容,后续所有替换都在 result 上操作,避免直接修改入参\n let result = content\n // 遍历用户传进来的所有变量键值对,Object.entries 会把对象变成 [key, value] 数组\n \n for (const [key, value] of Object.entries(variables)) {\n // 构造正则:把 key 前后加上 {{ 和 }},并用双反斜杠转义花括号,使其成为普通字符;g 标志表示全局匹配,一行出现多次也能全部替换\n // 在字符串字面量里,反斜杠本身需要被转义,所以用“\\\\”才能得到一个真正的反斜杠;\n // 正则中 { 是特殊字符,需要写成 \\{ 来匹配字面量“{”,因此代码里就是 \\\\{。\n // 之所以要“\\\\{”而不是“\\{”,是因为 JS 字符串里先解析一次转义,正则引擎再解析一次,\n // 所以写两个反斜杠才能保证最终正则拿到的是“\\{”这个“字面量左花括号”。\n// 转义使用的是“反斜杠”(\\)符号,在字符串字面量里需要写成“\\\\”才能表示一个真正的反斜杠。\n const regex = new RegExp(`\\\\{\\\\{${key}\\\\}\\\\}`, 'g')\n // 用 replace 方法把匹配到的 {{key}} 全部替换成对应的 value,并把结果重新赋给 result,实现累积替换\n result = result.replace(regex, value)\n }\n // 返回经过所有变量替换后的最终字符串\n return result\n}\n\n/**\n * 在指定目录下使用指定包管理器安装依赖。\n * 默认使用 pnpm,也可传入 npm、yarn 等。\n */\nexport async function installDependencies(targetDir: string, packageManager: string = 'pnpm') {\n // 动态导入 child_process 的 execSync,避免顶层引入\n const { execSync } = await import('child_process') \n // 提示用户正在安装依赖,青色输出\n console.log(chalk.cyan(`\\n正在使用 ${packageManager} 安装依赖...`))\n try {\n // 在目标目录执行 install 命令,stdio: 'inherit' 让子进程输出直接显示到当前终端\n execSync(`${packageManager} install`, { cwd: targetDir, stdio: 'inherit' })\n // 成功提示,绿色勾\n console.log(chalk.green('✓ 依赖安装完成'))\n } catch (error) {\n // 失败提示,黄色警告\n console.log(chalk.yellow('依赖安装失败,请手动安装'))\n }\n}\n\n/**\n * 在指定目录初始化 Git 仓库。\n */\nexport async function initGit(targetDir: string) {\n const { execSync } = await import('child_process')\n try {\n execSync('git init', { cwd: targetDir, stdio: 'inherit' })\n console.log(chalk.green('✓ Git 仓库初始化完成'))\n } catch (error) {\n console.log(chalk.yellow('Git 初始化失败,请手动初始化'))\n }\n}"],"mappings":"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","names":["import_chalk","inquirer","fs","path","chalk","import_path","import_fs_extra","chalk","path","fs"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// node_modules/.pnpm/tsup@8.5.1_typescript@5.9.3/node_modules/tsup/assets/esm_shims.js
|
|
4
|
+
import path from "path";
|
|
5
|
+
import { fileURLToPath } from "url";
|
|
6
|
+
var getFilename = () => fileURLToPath(import.meta.url);
|
|
7
|
+
var getDirname = () => path.dirname(getFilename());
|
|
8
|
+
var __dirname = /* @__PURE__ */ getDirname();
|
|
9
|
+
|
|
10
|
+
// src/index.ts
|
|
11
|
+
import { Command } from "commander";
|
|
12
|
+
import chalk2 from "chalk";
|
|
13
|
+
|
|
14
|
+
// src/prompts.ts
|
|
15
|
+
import inquirer from "inquirer";
|
|
16
|
+
async function askScaffoldQuestions() {
|
|
17
|
+
const answers = await inquirer.prompt([
|
|
18
|
+
{
|
|
19
|
+
name: "projectName",
|
|
20
|
+
message: "\u9879\u76EE\u540D\u79F0\uFF1A",
|
|
21
|
+
type: "input",
|
|
22
|
+
validate: (input) => input.trim() ? true : "\u8BF7\u8F93\u5165\u9879\u76EE\u540D\u79F0"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: "description",
|
|
26
|
+
message: "\u9879\u76EE\u63CF\u8FF0\uFF1A",
|
|
27
|
+
type: "input",
|
|
28
|
+
default: "Admin & Big-screen scaffold project"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: "templates",
|
|
32
|
+
message: "\u8BF7\u9009\u62E9\u9700\u8981\u7684\u6A21\u677F\uFF1A",
|
|
33
|
+
type: "checkbox",
|
|
34
|
+
choices: [
|
|
35
|
+
{ name: "\u540E\u53F0\u7BA1\u7406\uFF08admin-portal\uFF09", value: "admin-portal", checked: true },
|
|
36
|
+
{ name: "\u6570\u636E\u5927\u5C4F\uFF08dashboard-bigscreen\uFF09", value: "dashboard-bigscreen" },
|
|
37
|
+
{ name: "Mock \u670D\u52A1\uFF08mock-service\uFF09", value: "mock-service" }
|
|
38
|
+
],
|
|
39
|
+
validate: (list) => list.length ? true : "\u81F3\u5C11\u9009\u62E9\u4E00\u4E2A\u6A21\u677F"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: "enableMock",
|
|
43
|
+
message: "\u662F\u5426\u542F\u7528\u5185\u7F6E Mock\uFF1F",
|
|
44
|
+
type: "confirm",
|
|
45
|
+
default: true
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: "enableAI",
|
|
49
|
+
message: "\u662F\u5426\u52A0\u5165 AI \u6A21\u5757\uFF1F",
|
|
50
|
+
type: "confirm",
|
|
51
|
+
default: false
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: "enableDeploy",
|
|
55
|
+
message: "\u662F\u5426\u751F\u6210\u90E8\u7F72\u811A\u672C\uFF08Docker/CI\uFF09\uFF1F",
|
|
56
|
+
type: "confirm",
|
|
57
|
+
default: true
|
|
58
|
+
}
|
|
59
|
+
]);
|
|
60
|
+
return answers;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// src/utils.ts
|
|
64
|
+
import fs from "fs-extra";
|
|
65
|
+
import path2 from "path";
|
|
66
|
+
import chalk from "chalk";
|
|
67
|
+
async function copyTemplate(templateDir, targetDir, variables) {
|
|
68
|
+
const files = await fs.readdir(templateDir);
|
|
69
|
+
for (const file of files) {
|
|
70
|
+
const srcPath = path2.join(templateDir, file);
|
|
71
|
+
const destPath = path2.join(targetDir, file);
|
|
72
|
+
const stat = await fs.stat(srcPath);
|
|
73
|
+
if (stat.isDirectory()) {
|
|
74
|
+
await fs.ensureDir(destPath);
|
|
75
|
+
await copyTemplate(srcPath, destPath, variables);
|
|
76
|
+
} else {
|
|
77
|
+
let content = await fs.readFile(srcPath, "utf-8");
|
|
78
|
+
content = replaceVariables(content, variables);
|
|
79
|
+
await fs.writeFile(destPath, content);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function replaceVariables(content, variables) {
|
|
84
|
+
let result = content;
|
|
85
|
+
for (const [key, value] of Object.entries(variables)) {
|
|
86
|
+
const regex = new RegExp(`\\{\\{${key}\\}\\}`, "g");
|
|
87
|
+
result = result.replace(regex, value);
|
|
88
|
+
}
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
91
|
+
async function installDependencies(targetDir, packageManager = "pnpm") {
|
|
92
|
+
const { execSync } = await import("child_process");
|
|
93
|
+
console.log(chalk.cyan(`
|
|
94
|
+
\u6B63\u5728\u4F7F\u7528 ${packageManager} \u5B89\u88C5\u4F9D\u8D56...`));
|
|
95
|
+
try {
|
|
96
|
+
execSync(`${packageManager} install`, { cwd: targetDir, stdio: "inherit" });
|
|
97
|
+
console.log(chalk.green("\u2713 \u4F9D\u8D56\u5B89\u88C5\u5B8C\u6210"));
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.log(chalk.yellow("\u4F9D\u8D56\u5B89\u88C5\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u5B89\u88C5"));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async function initGit(targetDir) {
|
|
103
|
+
const { execSync } = await import("child_process");
|
|
104
|
+
try {
|
|
105
|
+
execSync("git init", { cwd: targetDir, stdio: "inherit" });
|
|
106
|
+
console.log(chalk.green("\u2713 Git \u4ED3\u5E93\u521D\u59CB\u5316\u5B8C\u6210"));
|
|
107
|
+
} catch (error) {
|
|
108
|
+
console.log(chalk.yellow("Git \u521D\u59CB\u5316\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u521D\u59CB\u5316"));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// src/index.ts
|
|
113
|
+
import path3 from "path";
|
|
114
|
+
import fs2 from "fs-extra";
|
|
115
|
+
var program = new Command();
|
|
116
|
+
program.name("create-mvp").description("Admin & Big-screen project scaffold").version("0.1.0").action(async () => {
|
|
117
|
+
try {
|
|
118
|
+
console.log(chalk2.cyan("\n\u6B22\u8FCE\u4F7F\u7528 create-mvp \u811A\u624B\u67B6\uFF01\n"));
|
|
119
|
+
const answers = await askScaffoldQuestions();
|
|
120
|
+
const targetDir = path3.join(process.cwd(), answers.projectName);
|
|
121
|
+
if (await fs2.pathExists(targetDir)) {
|
|
122
|
+
console.log(chalk2.red(`
|
|
123
|
+
\u76EE\u5F55 ${answers.projectName} \u5DF2\u5B58\u5728\uFF01`));
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
console.log(chalk2.cyan(`
|
|
127
|
+
\u6B63\u5728\u521B\u5EFA\u9879\u76EE ${answers.projectName}...`));
|
|
128
|
+
for (const template of answers.templates) {
|
|
129
|
+
const templateDir = path3.join(__dirname, "../templates", template);
|
|
130
|
+
await copyTemplate(templateDir, targetDir, {
|
|
131
|
+
projectName: answers.projectName,
|
|
132
|
+
description: answers.description
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
console.log(chalk2.green("\u2713 \u9879\u76EE\u521B\u5EFA\u5B8C\u6210"));
|
|
136
|
+
await initGit(targetDir);
|
|
137
|
+
await installDependencies(targetDir);
|
|
138
|
+
console.log(chalk2.cyan("\n\u9879\u76EE\u521B\u5EFA\u6210\u529F\uFF01"));
|
|
139
|
+
console.log(chalk2.yellow(`
|
|
140
|
+
\u8BF7\u8FDB\u5165\u9879\u76EE\u76EE\u5F55\uFF1A`));
|
|
141
|
+
console.log(chalk2.white(` cd ${answers.projectName}`));
|
|
142
|
+
console.log(chalk2.yellow(`
|
|
143
|
+
\u542F\u52A8\u5F00\u53D1\u670D\u52A1\u5668\uFF1A`));
|
|
144
|
+
console.log(chalk2.white(` npm run dev`));
|
|
145
|
+
console.log(chalk2.yellow(`
|
|
146
|
+
\u6784\u5EFA\u9879\u76EE\uFF1A`));
|
|
147
|
+
console.log(chalk2.white(` npm run build`));
|
|
148
|
+
console.log(chalk2.yellow(`
|
|
149
|
+
\u8FD0\u884C\u6D4B\u8BD5\uFF1A`));
|
|
150
|
+
console.log(chalk2.white(` npm run test:unit`));
|
|
151
|
+
console.log(chalk2.white(` npm run test:e2e`));
|
|
152
|
+
console.log(chalk2.cyan("\n\u795D\u4F60\u5F00\u53D1\u6109\u5FEB\uFF01\n"));
|
|
153
|
+
} catch (error) {
|
|
154
|
+
console.log(chalk2.red("\n\u9879\u76EE\u521B\u5EFA\u5931\u8D25\uFF1A"), error);
|
|
155
|
+
process.exit(1);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
program.parse();
|
|
159
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../node_modules/.pnpm/tsup@8.5.1_typescript@5.9.3/node_modules/tsup/assets/esm_shims.js","../src/index.ts","../src/prompts.ts","../src/utils.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","#!/usr/bin/env node\nimport { Command } from 'commander'\nimport chalk from 'chalk'\nimport { askScaffoldQuestions } from './prompts'\nimport { copyTemplate, installDependencies, initGit } from './utils'\nimport path from 'path'\nimport fs from 'fs-extra'\n\nconst program = new Command()\n\nprogram\n .name('create-mvp')\n .description('Admin & Big-screen project scaffold')\n .version('0.1.0')\n .action(async () => {\n try {\n console.log(chalk.cyan('\\n欢迎使用 create-mvp 脚手架!\\n'))\n\n const answers = await askScaffoldQuestions()\n\n const targetDir = path.join(process.cwd(), answers.projectName)\n\n if (await fs.pathExists(targetDir)) {\n console.log(chalk.red(`\\n目录 ${answers.projectName} 已存在!`))\n return\n }\n\n console.log(chalk.cyan(`\\n正在创建项目 ${answers.projectName}...`))\n\n for (const template of answers.templates) {\n const templateDir = path.join(__dirname, '../templates', template)\n await copyTemplate(templateDir, targetDir, {\n projectName: answers.projectName,\n description: answers.description,\n })\n }\n\n console.log(chalk.green('✓ 项目创建完成'))\n\n await initGit(targetDir)\n\n await installDependencies(targetDir)\n\n console.log(chalk.cyan('\\n项目创建成功!'))\n console.log(chalk.yellow(`\\n请进入项目目录:`))\n console.log(chalk.white(` cd ${answers.projectName}`))\n console.log(chalk.yellow(`\\n启动开发服务器:`))\n console.log(chalk.white(` npm run dev`))\n console.log(chalk.yellow(`\\n构建项目:`))\n console.log(chalk.white(` npm run build`))\n console.log(chalk.yellow(`\\n运行测试:`))\n console.log(chalk.white(` npm run test:unit`))\n console.log(chalk.white(` npm run test:e2e`))\n console.log(chalk.cyan('\\n祝你开发愉快!\\n'))\n } catch (error) {\n console.log(chalk.red('\\n项目创建失败:'), error)\n process.exit(1)\n }\n })\n\nprogram.parse()\n","/*\n * @Author: xhp 837792102@qq.com\n * @Date: 2026-01-23 14:44:30\n * @LastEditors: xhp 837792102@qq.com\n * @LastEditTime: 2026-01-23 16:39:21\n * @FilePath: /admin-mvp/packages/cli/src/prompts.ts\n * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE\n */\n// 导入 inquirer 模块,用于交互式命令行提示\nimport inquirer from 'inquirer'\n\n// 定义 ScaffoldAnswers 类型,用于存储脚手架问题的答案\nexport type ScaffoldAnswers = {\n \n // 项目名称:用户输入的项目名称字符串\n projectName: string\n \n // 项目描述:用户输入的项目描述信息\n description: string\n \n // 模板选择:用户选择的模板数组,可能包含 'admin-portal'、'dashboard-bigscreen'、'mock-service' 等\n templates: string[]\n \n // 是否启用 Mock:布尔值,表示是否启用内置的 Mock 服务\n enableMock: boolean\n \n // 是否启用 AI:布尔值,表示是否加入 AI 模块功能\n enableAI: boolean\n \n // 是否生成部署脚本:布尔值,表示是否生成 Docker/CI 相关的部署配置文件\n enableDeploy: boolean\n}\n\n\nexport async function askScaffoldQuestions(): Promise<ScaffoldAnswers> {\n const answers = await inquirer.prompt([\n {\n name: 'projectName',\n message: '项目名称:',\n type: 'input',\n validate: (input: string) => (input.trim() ? true : '请输入项目名称'),\n },\n {\n name: 'description',\n message: '项目描述:',\n type: 'input',\n default: 'Admin & Big-screen scaffold project',\n },\n {\n name: 'templates',\n message: '请选择需要的模板:',\n type: 'checkbox',\n choices: [\n { name: '后台管理(admin-portal)', value: 'admin-portal', checked: true },\n { name: '数据大屏(dashboard-bigscreen)', value: 'dashboard-bigscreen' },\n { name: 'Mock 服务(mock-service)', value: 'mock-service' },\n ],\n validate: (list: string[]) => (list.length ? true : '至少选择一个模板'),\n },\n {\n name: 'enableMock',\n message: '是否启用内置 Mock?',\n type: 'confirm',\n default: true,\n },\n {\n name: 'enableAI',\n message: '是否加入 AI 模块?',\n type: 'confirm',\n default: false,\n },\n {\n name: 'enableDeploy',\n message: '是否生成部署脚本(Docker/CI)?',\n type: 'confirm',\n default: true,\n },\n ])\n\n return answers as ScaffoldAnswers\n}","// 引入第三方库:fs-extra 是对 Node 原生 fs 的增强,path 用于路径拼接,chalk 用于终端彩色输出\n// 这行代码导入了一个叫 fs-extra 的库,它扩展了 Node.js 内置的 fs (文件系统)模块,提供了更多实用的文件操作功能。\nimport fs from 'fs-extra'\n//这行代码导入 Node.js 内置的 path 模块,用来处理文件和目录路径。\nimport path from 'path'\n//这行代码导入 chalk 库,可以在终端输出彩色的文字,让信息更清晰。\nimport chalk from 'chalk'\n\n/**\n * 递归地把模板目录 templateDir 中的所有文件/文件夹复制到目标目录 targetDir,\n * 并在复制文件内容时根据 variables 做变量替换({{变量名}} → 实际值)。\n */\n\n//这行定义了一个异步函数 copyTemplate ,并将其导出供其他文件使用。 async 表示这是一个异步函数。\nexport async function copyTemplate(\n //这是函数的第一个参数 templateDir ,类型是字符串,表示模板目录的路径。\n templateDir: string, // 模板目录绝对路径\n //这是函数的第二个参数 targetDir ,类型是字符串,表示目标目录的路径。\n targetDir: string, \n //这是函数的第三个参数 variables ,是一个键值都是字符串的对象,用来存储要替换的变量。 // 目标目录绝对路径\n variables: Record<string, string> // 变量键值对,如 { projectName: 'my-app' }\n) {\n // 读取模板目录下的所有文件/文件夹名\n //这行读取模板目录下的所有文件和子目录名,存到 files 变量中。 await 表示等待异步操作完成。\n \n // readdir 返回的是 string[],即模板目录下所有文件/文件夹的名字数组\n // readdir 返回的是一个 string[] 类型的数组,例如:\n // 假设 templateDir 目录下有以下文件和子目录:\n // - package.json\n // - src/\n // - .gitignore\n // 那么 files 的值就是:\n // ['package.json', 'src', '.gitignore']\n const files: string[] = await fs.readdir(templateDir) // readdir 返回 Promise<string[]>,必须用 await 等待异步结果,才能继续后续同步遍历\n\n // 逐个处理\n for (const file of files) {\n // `files` 里只是“文件名/子目录名”,并不包含父路径;\n // 为了拿到完整路径去读取或递归,必须把 templateDir 拼回去。\n // 举例:假设 templateDir = '/tmp/template',file = 'src/App.vue'\n // 那么 path.join(templateDir, file) 会返回 '/tmp/template/src/App.vue'\n\n // 递归调用时,上一层把 templateDir 已经拼到了“当前层级”目录,\n // 因此这一层只需把 file(当前层级的子文件/子目录名)再拼上去,\n // 就能拿到从最初模板根目录开始的完整路径。\n // 举例:\n // 第1层:templateDir = /tmp/template\n // file = src\n // → srcPath = /tmp/template/src\n // 第2层:templateDir = /tmp/template/src (上一层递归传进来的)\n // file = App.vue\n // → srcPath = /tmp/template/src/App.vue\n const srcPath = path.join(templateDir, file) // path.join 只是纯字符串拼接,同步立即返回,无需 await\n const destPath = path.join(targetDir, file) // 同上,同步操作\n const stat = await fs.stat(srcPath) // fs.stat 需要访问磁盘,是异步 I/O,必须 await 等待结果\n\n if (stat.isDirectory()) {\n // 如果是目录:先确保目标目录存在,再递归复制\n await fs.ensureDir(destPath)\n await copyTemplate(srcPath, destPath, variables)\n } else {\n // 如果是文件:读取内容 → 替换变量 → 写入目标路径\n let content = await fs.readFile(srcPath, 'utf-8')\n // replaceVariables 是一个自定义工具函数,作用是把文件内容里出现的 {{变量名}} 占位符\n // 全部替换成用户传入的对应值。举例:content 里有 \"{{projectName}}\",variables 里给出\n // { projectName: 'my-app' },执行后这段文本会变成 \"my-app\"。\n // 因为 replaceVariables 返回的是替换后的全新字符串,必须重新赋值给 content,\n // 否则后续 writeFile 写入的还是原来的旧内容,变量替换就白做了。\n content = replaceVariables(content, variables)\n await fs.writeFile(destPath, content)\n }\n }\n}\n\n/**\n * 将文本中出现的 {{key}} 全部替换为对应的 value。\n * 支持全局替换(一行里出现多次也能全部替换)。\n */\nfunction replaceVariables(content: string, variables: Record<string, string>): string {\n // 用 result 变量保存一份原始内容,后续所有替换都在 result 上操作,避免直接修改入参\n let result = content\n // 遍历用户传进来的所有变量键值对,Object.entries 会把对象变成 [key, value] 数组\n \n for (const [key, value] of Object.entries(variables)) {\n // 构造正则:把 key 前后加上 {{ 和 }},并用双反斜杠转义花括号,使其成为普通字符;g 标志表示全局匹配,一行出现多次也能全部替换\n // 在字符串字面量里,反斜杠本身需要被转义,所以用“\\\\”才能得到一个真正的反斜杠;\n // 正则中 { 是特殊字符,需要写成 \\{ 来匹配字面量“{”,因此代码里就是 \\\\{。\n // 之所以要“\\\\{”而不是“\\{”,是因为 JS 字符串里先解析一次转义,正则引擎再解析一次,\n // 所以写两个反斜杠才能保证最终正则拿到的是“\\{”这个“字面量左花括号”。\n// 转义使用的是“反斜杠”(\\)符号,在字符串字面量里需要写成“\\\\”才能表示一个真正的反斜杠。\n const regex = new RegExp(`\\\\{\\\\{${key}\\\\}\\\\}`, 'g')\n // 用 replace 方法把匹配到的 {{key}} 全部替换成对应的 value,并把结果重新赋给 result,实现累积替换\n result = result.replace(regex, value)\n }\n // 返回经过所有变量替换后的最终字符串\n return result\n}\n\n/**\n * 在指定目录下使用指定包管理器安装依赖。\n * 默认使用 pnpm,也可传入 npm、yarn 等。\n */\nexport async function installDependencies(targetDir: string, packageManager: string = 'pnpm') {\n // 动态导入 child_process 的 execSync,避免顶层引入\n const { execSync } = await import('child_process') \n // 提示用户正在安装依赖,青色输出\n console.log(chalk.cyan(`\\n正在使用 ${packageManager} 安装依赖...`))\n try {\n // 在目标目录执行 install 命令,stdio: 'inherit' 让子进程输出直接显示到当前终端\n execSync(`${packageManager} install`, { cwd: targetDir, stdio: 'inherit' })\n // 成功提示,绿色勾\n console.log(chalk.green('✓ 依赖安装完成'))\n } catch (error) {\n // 失败提示,黄色警告\n console.log(chalk.yellow('依赖安装失败,请手动安装'))\n }\n}\n\n/**\n * 在指定目录初始化 Git 仓库。\n */\nexport async function initGit(targetDir: string) {\n const { execSync } = await import('child_process')\n try {\n execSync('git init', { cwd: targetDir, stdio: 'inherit' })\n console.log(chalk.green('✓ Git 仓库初始化完成'))\n } catch (error) {\n console.log(chalk.yellow('Git 初始化失败,请手动初始化'))\n }\n}"],"mappings":"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","names":["chalk","path","path","fs","chalk"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-admin-mvp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Admin & Big-screen project scaffold",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"create-admin-mvp": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"templates"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsup",
|
|
16
|
+
"dev": "tsup --watch",
|
|
17
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"scaffold",
|
|
21
|
+
"cli",
|
|
22
|
+
"template",
|
|
23
|
+
"vue",
|
|
24
|
+
"typescript",
|
|
25
|
+
"vite"
|
|
26
|
+
],
|
|
27
|
+
"author": "",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"chalk": "^5.6.2",
|
|
31
|
+
"commander": "^14.0.2",
|
|
32
|
+
"fs-extra": "^11.3.3",
|
|
33
|
+
"inquirer": "^13.2.1"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@types/fs-extra": "^11.0.4",
|
|
37
|
+
"@types/node": "^25.0.10",
|
|
38
|
+
"tsup": "^8.5.1",
|
|
39
|
+
"typescript": "^5.9.3"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// filepath: /Users/xuhuiping/admin-mvp/packages/cli/templates/admin-portal/.stylelintrc.cjs
|
|
2
|
+
// Stylelint 配置文件
|
|
3
|
+
// 检查 CSS/SCSS/Less 代码规范
|
|
4
|
+
|
|
5
|
+
module.exports = {
|
|
6
|
+
extends: [
|
|
7
|
+
'stylelint-config-standard', // 标准 CSS 规范
|
|
8
|
+
'stylelint-config-recommended-vue', // Vue 文件规范
|
|
9
|
+
'stylelint-config-prettier', // 关闭与 Prettier 冲突的规则
|
|
10
|
+
],
|
|
11
|
+
rules: {
|
|
12
|
+
'selector-class-pattern': null, // 关闭类名模式检查
|
|
13
|
+
'no-descending-specificity': null, // 关闭特异性检查
|
|
14
|
+
'comment-empty-line-before': null, // 关闭注释前空行检查
|
|
15
|
+
'number-leading-zero': null, // 关闭数字前导零检查
|
|
16
|
+
'rule-empty-line-before': null,// 关闭规则前空行检查
|
|
17
|
+
'value-keyword-case': null, // 关闭值的大小写检查
|
|
18
|
+
'color-function-notation': null, // 关闭颜色函数表示法检查
|
|
19
|
+
'alpha-value-notation': null, // 关闭透明度值表示法检查
|
|
20
|
+
'selector-id-pattern': null, // 关闭ID选择器模式检查
|
|
21
|
+
'selector-type-no-unknown': null, // 关闭未知类型选择器检查
|
|
22
|
+
'selector-pseudo-class-no-unknown': [
|
|
23
|
+
true, // 允许deep伪类
|
|
24
|
+
{
|
|
25
|
+
ignorePseudoClasses: ['deep'],
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
overrides: [
|
|
30
|
+
{
|
|
31
|
+
files: ['**/*.vue'],
|
|
32
|
+
customSyntax: 'postcss-html', // Vue 文件使用 postcss-html 语法
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
files: ['**/*.less'],
|
|
36
|
+
customSyntax: 'postcss-less', // Less 文件使用 postcss-less 语法
|
|
37
|
+
},
|
|
38
|
+
]
|
|
39
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# .dockerignore
|
|
2
|
+
# Docker 构建时忽略的文件和目录
|
|
3
|
+
|
|
4
|
+
# 依赖
|
|
5
|
+
node_modules
|
|
6
|
+
npm-debug.log
|
|
7
|
+
yarn-error.log
|
|
8
|
+
|
|
9
|
+
# 构建产物
|
|
10
|
+
dist
|
|
11
|
+
build
|
|
12
|
+
|
|
13
|
+
# 测试
|
|
14
|
+
coverage
|
|
15
|
+
.nyc_output
|
|
16
|
+
|
|
17
|
+
# IDE
|
|
18
|
+
.vscode
|
|
19
|
+
.idea
|
|
20
|
+
*.swp
|
|
21
|
+
*.swo
|
|
22
|
+
*~
|
|
23
|
+
|
|
24
|
+
# Git
|
|
25
|
+
.git
|
|
26
|
+
.gitignore
|
|
27
|
+
.gitattributes
|
|
28
|
+
|
|
29
|
+
# Docker
|
|
30
|
+
Dockerfile
|
|
31
|
+
docker-compose.yml
|
|
32
|
+
.dockerignore
|
|
33
|
+
|
|
34
|
+
# CI/CD
|
|
35
|
+
.github
|
|
36
|
+
.gitlab-ci.yml
|
|
37
|
+
.travis.yml
|
|
38
|
+
|
|
39
|
+
# 文档
|
|
40
|
+
README.md
|
|
41
|
+
CHANGELOG.md
|
|
42
|
+
LICENSE
|
|
43
|
+
|
|
44
|
+
# 环境变量
|
|
45
|
+
.env
|
|
46
|
+
.env.local
|
|
47
|
+
.env.*.local
|
|
48
|
+
|
|
49
|
+
# 临时文件
|
|
50
|
+
*.log
|
|
51
|
+
*.tmp
|
|
52
|
+
.cache
|
|
53
|
+
.DS_Store
|
|
54
|
+
Thumbs.db
|
|
55
|
+
|
|
56
|
+
# 其他
|
|
57
|
+
.editorconfig
|
|
58
|
+
.prettierrc
|
|
59
|
+
.eslintrc
|
|
60
|
+
.stylelintrc
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# 通用环境变量
|
|
2
|
+
# 所有环境都会使用的变量
|
|
3
|
+
|
|
4
|
+
# 应用名称
|
|
5
|
+
VITE_APP_NAME={{projectName}}
|
|
6
|
+
|
|
7
|
+
# 应用描述
|
|
8
|
+
VITE_APP_DESCRIPTION={{description}}
|
|
9
|
+
|
|
10
|
+
# 应用版本
|
|
11
|
+
VITE_APP_VERSION=0.0.0
|
|
12
|
+
|
|
13
|
+
# API 基础 URL
|
|
14
|
+
VITE_API_BASE_URL=/api
|
|
15
|
+
|
|
16
|
+
# API 超时时间(毫秒)
|
|
17
|
+
VITE_API_TIMEOUT=30000
|
|
18
|
+
|
|
19
|
+
# 是否启用 Mock 数据
|
|
20
|
+
VITE_ENABLE_MOCK=true
|
|
21
|
+
|
|
22
|
+
# 是否启用性能监控
|
|
23
|
+
VITE_ENABLE_PERFORMANCE=false
|
|
24
|
+
|
|
25
|
+
# 是否启用错误监控
|
|
26
|
+
VITE_ENABLE_ERROR_TRACKING=false
|
|
27
|
+
|
|
28
|
+
# 是否启用用户行为分析
|
|
29
|
+
VITE_ENABLE_USER_ANALYTICS=false
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# 开发环境变量
|
|
2
|
+
# 开发环境(npm run dev)会使用这些变量
|
|
3
|
+
|
|
4
|
+
# 环境模式
|
|
5
|
+
NODE_ENV=development
|
|
6
|
+
|
|
7
|
+
# API 基础 URL(开发环境)
|
|
8
|
+
VITE_API_BASE_URL=http://localhost:3000/api
|
|
9
|
+
|
|
10
|
+
# 是否启用 Mock 数据(开发环境)
|
|
11
|
+
VITE_ENABLE_MOCK=true
|
|
12
|
+
|
|
13
|
+
# 是否启用性能监控(开发环境)
|
|
14
|
+
VITE_ENABLE_PERFORMANCE=true
|
|
15
|
+
|
|
16
|
+
# 是否启用错误监控(开发环境)
|
|
17
|
+
VITE_ENABLE_ERROR_TRACKING=true
|
|
18
|
+
|
|
19
|
+
# 是否启用用户行为分析(开发环境)
|
|
20
|
+
VITE_ENABLE_USER_ANALYTICS=true
|
|
21
|
+
|
|
22
|
+
# 是否启用热更新
|
|
23
|
+
VITE_HMR=true
|
|
24
|
+
|
|
25
|
+
# 是否启用 Source Map(方便调试)
|
|
26
|
+
VITE_SOURCE_MAP=true
|
|
27
|
+
|
|
28
|
+
# 是否启用 ESLint
|
|
29
|
+
VITE_ENABLE_ESLINT=true
|
|
30
|
+
|
|
31
|
+
# 是否启用 Prettier
|
|
32
|
+
VITE_ENABLE_PRETTIER=true
|
|
33
|
+
|
|
34
|
+
# 是否启用 Stylelint
|
|
35
|
+
VITE_ENABLE_STYLELINT=true
|
|
36
|
+
|
|
37
|
+
# 是否启用 Vitest
|
|
38
|
+
VITE_ENABLE_VITEST=true
|
|
39
|
+
|
|
40
|
+
# 是否启用 Playwright
|
|
41
|
+
VITE_ENABLE_PLAYWRIGHT=true
|