完善 脚手架UI
This commit is contained in:
@ -5,154 +5,212 @@ export const projectTypes = [
|
||||
{ name: "全栈", desc: "前后端一体化" },
|
||||
];
|
||||
|
||||
// 三级菜单 - 具体框架
|
||||
export const frameworks = {
|
||||
// 框架选项
|
||||
export const frameworkOptions = {
|
||||
前端: [
|
||||
{ name: "React", desc: "Vite + React", value: "react-vite" },
|
||||
{ name: "Vue", desc: "Vite + Vue", value: "vue-vite" },
|
||||
{ value: "vue", label: "Vue(Vite + Vue)" },
|
||||
{ value: "react", label: "React(Vite + React)" },
|
||||
],
|
||||
后端: [
|
||||
{ name: "Bun", desc: "Bun运行时", value: "bun" },
|
||||
{ name: "NestJS", desc: "企业级框架", value: "nestjs" },
|
||||
{ name: "Express", desc: "Express Generator", value: "express" },
|
||||
{ name: "Koa", desc: "Koa Generator", value: "koa" },
|
||||
{ name: "Egg", desc: "阿里Egg.js", value: "egg" },
|
||||
{ name: "Midway", desc: "阿里Midway", value: "midway" },
|
||||
{ name: "Fastify", desc: "高性能框架", value: "fastify" },
|
||||
{ name: "AdonisJS", desc: "全功能MVC", value: "adonisjs" },
|
||||
{ value: "bun", label: "Bun(Bun运行时)" },
|
||||
{ value: "node", label: "Node.js(Node运行时)" },
|
||||
],
|
||||
全栈: [
|
||||
{ name: "Next.js", desc: "React全栈框架", value: "nextjs" },
|
||||
{ name: "Nuxt", desc: "Vue全栈框架", value: "nuxt" },
|
||||
{ value: "nextjs", label: "Next.js(React全栈框架)" },
|
||||
{ value: "nuxt", label: "Nuxt(Vue全栈框架)" },
|
||||
],
|
||||
};
|
||||
|
||||
// 前端组件配置步骤
|
||||
export const frontendSteps = [
|
||||
{
|
||||
name: "路由",
|
||||
type: "select",
|
||||
message: "选择路由方案",
|
||||
options: [
|
||||
{ value: "none", label: "不需要路由" },
|
||||
{ value: "react-router", label: "React Router(React项目)" },
|
||||
{ value: "vue-router", label: "Vue Router(Vue项目)" },
|
||||
],
|
||||
default: "none"
|
||||
},
|
||||
{
|
||||
name: "状态管理",
|
||||
type: "select",
|
||||
message: "选择状态管理方案",
|
||||
options: [
|
||||
{ value: "none", label: "不需要状态管理" },
|
||||
{ value: "zustand", label: "Zustand(轻量级,React推荐)" },
|
||||
{ value: "pinia", label: "Pinia(Vue官方推荐)" },
|
||||
{ value: "redux", label: "Redux Toolkit(大型项目)" },
|
||||
{ value: "mobx", label: "MobX(响应式状态管理)" },
|
||||
],
|
||||
default: "none"
|
||||
},
|
||||
{
|
||||
name: "HTTP请求",
|
||||
type: "select",
|
||||
message: "选择HTTP请求库",
|
||||
options: [
|
||||
{ value: "none", label: "不需要HTTP库" },
|
||||
{ value: "axios", label: "Axios(功能全面,拦截器支持)" },
|
||||
{ value: "ky", label: "Ky(轻量级,基于Fetch)" },
|
||||
{ value: "ofetch", label: "ofetch(Nuxt团队出品)" },
|
||||
],
|
||||
default: "none"
|
||||
},
|
||||
{
|
||||
name: "UI组件库",
|
||||
type: "select",
|
||||
message: "选择UI组件库",
|
||||
options: [
|
||||
{ value: "none", label: "不需要UI库" },
|
||||
{ value: "antd", label: "Ant Design(企业级,React)" },
|
||||
{ value: "element-plus", label: "Element Plus(饿了么,Vue)" },
|
||||
{ value: "arco", label: "Arco Design(字节跳动)" },
|
||||
{ value: "naive-ui", label: "Naive UI(Vue3原生)" },
|
||||
{ value: "shadcn", label: "shadcn/ui(可定制,React)" },
|
||||
],
|
||||
default: "none"
|
||||
},
|
||||
{
|
||||
name: "CSS方案",
|
||||
type: "select",
|
||||
message: "选择CSS方案",
|
||||
options: [
|
||||
{ value: "none", label: "原生CSS" },
|
||||
{ value: "tailwind", label: "Tailwind CSS(原子化CSS)" },
|
||||
{ value: "unocss", label: "UnoCSS(即时原子化)" },
|
||||
{ value: "sass", label: "Sass/SCSS(预处理器)" },
|
||||
{ value: "less", label: "Less(预处理器)" },
|
||||
{ value: "styled", label: "Styled Components(CSS-in-JS)" },
|
||||
],
|
||||
default: "none"
|
||||
},
|
||||
{
|
||||
name: "工具库",
|
||||
type: "multiselect",
|
||||
message: "选择常用工具库",
|
||||
options: [
|
||||
{ value: "lodash", label: "Lodash(工具函数库)" },
|
||||
{ value: "dayjs", label: "Day.js(日期处理)" },
|
||||
{ value: "iconify", label: "Iconify(图标库)" },
|
||||
{ value: "vueuse", label: "VueUse(Vue组合式工具)" },
|
||||
{ value: "ahooks", label: "ahooks(React Hooks库)" },
|
||||
],
|
||||
default: []
|
||||
},
|
||||
{
|
||||
name: "表单验证",
|
||||
type: "select",
|
||||
message: "选择表单验证方案",
|
||||
options: [
|
||||
{ value: "none", label: "不需要表单验证" },
|
||||
{ value: "zod", label: "Zod(TypeScript优先)" },
|
||||
{ value: "yup", label: "Yup(声明式验证)" },
|
||||
{ value: "vee-validate", label: "VeeValidate(Vue专用)" },
|
||||
{ value: "react-hook-form", label: "React Hook Form" },
|
||||
],
|
||||
default: "none"
|
||||
},
|
||||
{
|
||||
name: "国际化",
|
||||
type: "select",
|
||||
message: "选择国际化方案",
|
||||
options: [
|
||||
{ value: "none", label: "不需要国际化" },
|
||||
{ value: "i18next", label: "i18next(通用方案)" },
|
||||
{ value: "vue-i18n", label: "Vue I18n(Vue专用)" },
|
||||
],
|
||||
default: "none"
|
||||
},
|
||||
{
|
||||
name: "代码规范",
|
||||
type: "multiselect",
|
||||
message: "选择代码规范工具",
|
||||
options: [
|
||||
{ value: "eslint", label: "ESLint(代码检查)" },
|
||||
{ value: "prettier", label: "Prettier(代码格式化)" },
|
||||
{ value: "husky", label: "Husky(Git Hooks)" },
|
||||
{ value: "lint-staged", label: "lint-staged(暂存区检查)" },
|
||||
{ value: "commitlint", label: "Commitlint(提交信息规范)" },
|
||||
],
|
||||
default: []
|
||||
},
|
||||
{
|
||||
name: "其他",
|
||||
type: "multiselect",
|
||||
message: "选择其他功能",
|
||||
options: [
|
||||
{ value: "mock", label: "Mock.js(模拟数据)" },
|
||||
{ value: "pwa", label: "PWA支持" },
|
||||
{ value: "storage", label: "持久化存储封装" },
|
||||
{ value: "env", label: "环境变量配置" },
|
||||
],
|
||||
default: []
|
||||
const bunComponents = {
|
||||
框架: [
|
||||
{ value: "normal", label: "原生" },
|
||||
{ value: "elysia", label: "Elysia(官方亲儿子)" },
|
||||
{ value: "hono", label: "Hono(轻量级)" },
|
||||
]
|
||||
};
|
||||
|
||||
const nodeComponents = {
|
||||
框架: [
|
||||
{ value: "nestjs", label: "NestJS(企业级框架)" },
|
||||
{ value: "express", label: "Express(Express Generator)" },
|
||||
{ value: "koa", label: "Koa(Koa Generator)" },
|
||||
{ value: "egg", label: "Egg(阿里Egg.js)" },
|
||||
{ value: "midway", label: "Midway(阿里Midway)" },
|
||||
{ value: "fastify", label: "Fastify(高性能框架)" },
|
||||
{ value: "adonisjs", label: "AdonisJS(全功能MVC)" },
|
||||
]
|
||||
};
|
||||
//后端公共框架
|
||||
const backendCommonComponents = {
|
||||
数据库: [
|
||||
{ value: "none", label: "不需要数据库" },
|
||||
{ value: "mongoose", label: "MongoDB + Mongoose" },
|
||||
{ value: "prisma", label: "Prisma(支持 MySQL / PostgreSQL / SQLite)" },
|
||||
{ value: "typeorm", label: "TypeORM(支持 MySQL / PostgreSQL 等)" },
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
|
||||
// 组件选项 - 按框架分类
|
||||
const reactComponents = {
|
||||
路由: [
|
||||
{ value: "none", label: "不需要路由" },
|
||||
{ value: "react-router", label: "React Router" },
|
||||
{ value: "tanstack-router", label: "TanStack Router" },
|
||||
],
|
||||
状态管理: [
|
||||
{ value: "none", label: "不需要状态管理" },
|
||||
{ value: "zustand", label: "Zustand(轻量级推荐)" },
|
||||
{ value: "redux", label: "Redux Toolkit" },
|
||||
{ value: "jotai", label: "Jotai(原子化)" },
|
||||
{ value: "mobx", label: "MobX" },
|
||||
],
|
||||
UI组件库: [
|
||||
{ value: "none", label: "不需要UI库" },
|
||||
{ value: "antd", label: "Ant Design" },
|
||||
{ value: "arco", label: "Arco Design" },
|
||||
{ value: "shadcn", label: "shadcn/ui" },
|
||||
{ value: "mui", label: "Material UI" },
|
||||
],
|
||||
表单验证: [
|
||||
{ value: "none", label: "不需要表单验证" },
|
||||
{ value: "react-hook-form", label: "React Hook Form" },
|
||||
{ value: "formik", label: "Formik" },
|
||||
{ value: "zod", label: "Zod" },
|
||||
],
|
||||
工具库: [
|
||||
{ value: "ahooks", label: "ahooks(React Hooks库)" },
|
||||
{ value: "lodash", label: "Lodash" },
|
||||
{ value: "dayjs", label: "Day.js" },
|
||||
{ value: "iconify", label: "Iconify图标" },
|
||||
],
|
||||
国际化: [
|
||||
{ value: "none", label: "不需要国际化" },
|
||||
{ value: "i18next", label: "i18next" },
|
||||
],
|
||||
};
|
||||
|
||||
const vueComponents = {
|
||||
路由: [
|
||||
{ value: "none", label: "不需要路由" },
|
||||
{ value: "vue-router", label: "Vue Router" },
|
||||
],
|
||||
状态管理: [
|
||||
{ value: "none", label: "不需要状态管理" },
|
||||
{ value: "pinia", label: "Pinia(官方推荐)" },
|
||||
],
|
||||
UI组件库: [
|
||||
{ value: "none", label: "不需要UI库" },
|
||||
{ value: "element-plus", label: "Element Plus" },
|
||||
{ value: "naive-ui", label: "Naive UI" },
|
||||
{ value: "arco-vue", label: "Arco Design Vue" },
|
||||
{ value: "ant-design-vue", label: "Ant Design Vue" },
|
||||
],
|
||||
表单验证: [
|
||||
{ value: "none", label: "不需要表单验证" },
|
||||
{ value: "vee-validate", label: "VeeValidate" },
|
||||
{ value: "vuelidate", label: "Vuelidate" },
|
||||
{ value: "zod", label: "Zod" },
|
||||
],
|
||||
工具库: [
|
||||
{ value: "vueuse", label: "VueUse(组合式工具)" },
|
||||
{ value: "lodash", label: "Lodash" },
|
||||
{ value: "dayjs", label: "Day.js" },
|
||||
{ value: "iconify", label: "Iconify图标" },
|
||||
], 国际化: [
|
||||
{ value: "none", label: "不需要国际化" },
|
||||
{ value: "vue-i18n", label: "Vue-i18n" },
|
||||
],
|
||||
};
|
||||
|
||||
// 通用组件(React和Vue共用)
|
||||
const commonComponents = {
|
||||
HTTP请求: [
|
||||
{ value: "none", label: "不需要HTTP库" },
|
||||
{ value: "axios", label: "Axios" },
|
||||
{ value: "ky", label: "Ky(轻量级)" },
|
||||
{ value: "ofetch", label: "ofetch" },
|
||||
],
|
||||
CSS方案: [
|
||||
{ value: "none", label: "原生CSS" },
|
||||
{ value: "tailwind", label: "Tailwind CSS" },
|
||||
{ value: "unocss", label: "UnoCSS" },
|
||||
{ value: "sass", label: "Sass/SCSS" },
|
||||
{ value: "less", label: "Less" },
|
||||
],
|
||||
代码规范: [
|
||||
{ value: "eslint", label: "ESLint" },
|
||||
{ value: "prettier", label: "Prettier" },
|
||||
{ value: "husky", label: "Husky" },
|
||||
{ value: "lint-staged", label: "lint-staged" },
|
||||
],
|
||||
其他: [
|
||||
{ value: "mock", label: "Mock.js" },
|
||||
{ value: "pwa", label: "PWA支持" },
|
||||
{ value: "storage", label: "持久化存储" },
|
||||
{ value: "threejs", label: "3D集成(Three.js)" },
|
||||
{ value: "babylonjs", label: "3D集成(Babylon.js)" },
|
||||
],
|
||||
};
|
||||
|
||||
// 根据框架获取组件配置
|
||||
export function getComponentsByFramework(framework) {
|
||||
if (!framework || framework === "none") return {};
|
||||
|
||||
const isReact = ["react", "nextjs"].includes(framework);
|
||||
const isVue = ["vue", "nuxt"].includes(framework);
|
||||
const isBun = framework === "bun";
|
||||
const isNode = framework === "node";
|
||||
|
||||
if (isReact) {
|
||||
return { ...reactComponents, ...commonComponents };
|
||||
} else if (isVue) {
|
||||
return { ...vueComponents, ...commonComponents };
|
||||
} else if (isBun) {
|
||||
return { ...bunComponents, ...backendCommonComponents };
|
||||
} else if (isNode) {
|
||||
return { ...nodeComponents, ...backendCommonComponents };
|
||||
}
|
||||
];
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// 获取默认框架
|
||||
function getDefaultFramework(projectType) {
|
||||
const opts = frameworkOptions[projectType];
|
||||
return opts?.[0]?.value || "none";
|
||||
}
|
||||
|
||||
// 生成前端/全栈项目的步骤配置
|
||||
export function generateSteps(projectType, selectedFramework) {
|
||||
const defaultFramework = getDefaultFramework(projectType);
|
||||
const framework = selectedFramework || defaultFramework;
|
||||
|
||||
const steps = [
|
||||
{
|
||||
name: "运行时",
|
||||
type: "select",
|
||||
message: "选择项目框架",
|
||||
options: frameworkOptions[projectType] || [],
|
||||
default: defaultFramework
|
||||
}
|
||||
];
|
||||
|
||||
const components = getComponentsByFramework(framework);
|
||||
const componentNames = Object.keys(components);
|
||||
|
||||
componentNames.forEach(name => {
|
||||
const isMulti = ["工具库", "代码规范", "其他"].includes(name);
|
||||
const opts = components[name] || [];
|
||||
steps.push({
|
||||
name,
|
||||
type: isMulti ? "multiselect" : "select",
|
||||
message: `选择${name}`,
|
||||
options: opts,
|
||||
default: isMulti ? [] : opts[0]?.value
|
||||
});
|
||||
});
|
||||
|
||||
return steps;
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import color from "picocolors";
|
||||
import { projectTypes, frameworks } from "./config.js";
|
||||
import { gridSelect, createComponentUI, formatResults, waitKey, showPlaceholder } from "./ui.js";
|
||||
import { projectTypes } from "./config.js";
|
||||
import { gridSelect, createScaffoldUI, formatResults, waitKey } from "./ui.js";
|
||||
|
||||
export async function run() {
|
||||
while (true) {
|
||||
@ -9,31 +9,16 @@ export async function run() {
|
||||
if (typeResult.action === "back") return "back";
|
||||
|
||||
const projectType = typeResult.item.name;
|
||||
const frameworkList = frameworks[projectType];
|
||||
|
||||
while (true) {
|
||||
// 三级菜单 - 框架选择
|
||||
const frameworkResult = await gridSelect(frameworkList, `${projectType}项目 - 选择框架`);
|
||||
if (frameworkResult.action === "back") break;
|
||||
// 三级页面 - 框架+组件配置(合并)
|
||||
const ui = createScaffoldUI(projectType);
|
||||
const result = await ui.runInteractive();
|
||||
|
||||
const framework = frameworkResult.item;
|
||||
|
||||
if (projectType === "前端" || projectType === "全栈") {
|
||||
// 组件配置
|
||||
const ui = createComponentUI(framework.name);
|
||||
const result = await ui.runInteractive();
|
||||
|
||||
if (result) {
|
||||
const summary = formatResults(result.results);
|
||||
ui.showSummary(summary);
|
||||
console.log(color.yellow("功能开发中,敬请期待..."));
|
||||
await waitKey();
|
||||
}
|
||||
} else {
|
||||
// 后端暂无组件配置
|
||||
showPlaceholder(framework);
|
||||
await waitKey();
|
||||
}
|
||||
if (result) {
|
||||
const summary = formatResults(result.steps, result.results);
|
||||
ui.showSummary(summary);
|
||||
console.log(color.yellow("功能开发中,敬请期待..."));
|
||||
await waitKey();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import color from "picocolors";
|
||||
import { initKeypress, onKey, stopKeypress } from "../keyboard.js";
|
||||
import { createStepUI } from "../utils/stepui.js";
|
||||
import { frontendSteps } from "./config.js";
|
||||
import { frameworkOptions, generateSteps } from "./config.js";
|
||||
|
||||
function clearScreen() {
|
||||
process.stdout.write('\x1Bc');
|
||||
@ -103,24 +103,24 @@ export async function gridSelect(items, title) {
|
||||
});
|
||||
}
|
||||
|
||||
// 创建组件配置UI
|
||||
export function createComponentUI(frameworkName) {
|
||||
// 创建框架+组件配置UI
|
||||
export function createScaffoldUI(projectType) {
|
||||
return createStepUI({
|
||||
title: `${frameworkName} - 组件配置`,
|
||||
getSteps: () => frontendSteps
|
||||
title: `${projectType} - 项目配置`,
|
||||
getSteps: () => generateSteps(projectType, null),
|
||||
onStepChange: (framework) => generateSteps(projectType, framework)
|
||||
});
|
||||
}
|
||||
|
||||
// 解析配置结果
|
||||
export function formatResults(results) {
|
||||
const stepNames = frontendSteps.map(s => s.name);
|
||||
export function formatResults(steps, results) {
|
||||
const summary = [];
|
||||
|
||||
results.forEach((val, i) => {
|
||||
if (Array.isArray(val) && val.length > 0) {
|
||||
summary.push(`${stepNames[i]}: ${val.join(", ")}`);
|
||||
summary.push(`${steps[i].name}: ${val.join(", ")}`);
|
||||
} else if (val && val !== "none") {
|
||||
summary.push(`${stepNames[i]}: ${val}`);
|
||||
summary.push(`${steps[i].name}: ${val}`);
|
||||
}
|
||||
});
|
||||
|
||||
@ -139,14 +139,3 @@ export async function waitKey(message = "按任意键返回") {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 显示占位信息
|
||||
export function showPlaceholder(framework) {
|
||||
clearScreen();
|
||||
console.log("");
|
||||
console.log(color.bgGreen(color.black(" 配置完成 ")));
|
||||
console.log("");
|
||||
console.log(color.cyan("框架: ") + framework.name);
|
||||
console.log("");
|
||||
console.log(color.yellow("功能开发中,敬请期待..."));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user