create-arena-project
Version:
神奇代码岛<->VSCode,从这里开始,创建一个神岛代码项目的脚手架。
228 lines (205 loc) • 7.84 kB
JavaScript
/**
* @fileoverview 神岛代码项目创建工具的入口文件
* 该文件负责处理用户交互,收集项目配置信息,并调用相关模块完成项目初始化
*/
import { default as chalk } from "chalk";
import { resolve, isAbsolute } from "path";
import yargs from "yargs";
import { hideBin } from "yargs/helpers";
import { install } from "./install.js";
import skeleton from "./skeleton.js";
import { ConfigWizard } from "./config-wizard.js";
import { errorHandler, ErrorType } from "./error-handler.js";
// 设置错误处理器
errorHandler.debug = process.env.DEBUG === "true";
/**
* 项目创建的核心逻辑
* @param {string} basepath - 项目基础路径
* @param {object} answers - 配置答案
* @param {object} selectedTemplate - 选定的模板
*/
async function createProject(basepath, answers, selectedTemplate = null) {
try {
// 显示项目创建进度
console.log(chalk.cyan("\n🚀 项目创建进度:"));
console.log(chalk.dim("----------------------------------------"));
// 步骤1:创建项目骨架
console.log(chalk.cyan("[1/3] 🏗️ 创建项目骨架"));
console.log(chalk.dim("• 生成目录结构"));
console.log(chalk.dim("• 配置基础文件"));
console.log(chalk.dim("• 设置开发环境"));
// 记录状态,但不创建日志文件
console.log(chalk.blue("[信息] [项目创建] 开始创建项目骨架"));
// 如果选择了项目模板,将模板信息添加到配置中
if (selectedTemplate) {
answers.template = { value: selectedTemplate.id };
}
await skeleton.skeleton(
isAbsolute(basepath) ? basepath : resolve(process.cwd(), basepath),
answers
);
console.log(chalk.green("✓ 项目骨架创建完成"));
console.log(chalk.blue("[信息] [项目创建] 项目骨架创建完成"));
// 步骤2:安装依赖
console.log(chalk.cyan("\n[2/3] 📦 安装项目依赖"));
console.log(chalk.dim("• 安装核心依赖"));
console.log(chalk.dim("• 安装开发工具"));
console.log(chalk.dim("• 配置构建脚本"));
// 记录状态
console.log(chalk.blue("[信息] [依赖安装] 开始安装项目依赖"));
await install(basepath, answers);
console.log(chalk.green("✓ 依赖安装完成"));
// 步骤3:完成配置
console.log(chalk.cyan("\n[3/3] ⚙️ 完成项目配置"));
console.log(chalk.dim("• 更新配置文件"));
console.log(chalk.dim("• 设置开发环境"));
console.log(chalk.dim("• 初始化版本控制"));
console.log(chalk.green("✓ 配置完成"));
console.log(chalk.dim("----------------------------------------"));
console.log(chalk.blue("[信息] [项目创建] 项目创建完成"));
} catch (error) {
await errorHandler.handleError(
error,
ErrorType.UNKNOWN,
"项目创建过程",
() => {
console.error(chalk.redBright("项目创建过程中发生错误:"), error);
}
);
process.exit(1);
}
// 显示项目创建成功的信息
const path = resolve(process.cwd(), basepath);
// 显示项目配置信息
console.log(chalk.yellowBright("\n📋 ArenaPro项目配置信息"));
console.log(chalk.dim("----------------------------------------"));
console.log(chalk.cyan("📁 项目目录:") + " " + path);
console.log(chalk.cyan("🔧 基础配置:"));
console.log(` • 开发语言: ${answers.languageType.value}`);
console.log(` • 代码规范: ${answers.prettier.value}`);
console.log(` • 国际化: ${answers.i18n.value}`);
console.log(
` • 项目类型:${answers.npmPackage.value}${
answers.isServer.value ? ` (${answers.isServer.value})` : ""
}`
);
if (selectedTemplate) {
console.log(chalk.cyan("\n📋 项目模板:"));
console.log(` • 模板名称:${selectedTemplate.name}`);
console.log(` • 模板特性:${selectedTemplate.features.join(", ")}`);
}
const entryExt = answers.languageType.value === "TypeScript" ? ".ts" : ".js";
console.log(chalk.cyan("\n⚙️ 共享代码:"));
console.log(` • ${path}/shares/sharesApp${entryExt}`);
if (!answers.isServer.value || answers.isServer.value === "服务端") {
console.log(chalk.cyan("\n⚙️ 服务端:"));
console.log(` • ${path}/server/src/App${entryExt}`);
}
if (!answers.isServer.value || answers.isServer.value === "客户端") {
console.log(chalk.cyan("\n⚙️ 客户端:"));
console.log(` • ${path}/client/src/clientApp${entryExt}`);
}
console.log(chalk.cyan("\n⚙️ 配置文件:"));
console.log(` • ${path}/dao3.config.json`);
console.log(chalk.dim("----------------------------------------"));
console.log(chalk.green("\n✨ 恭喜!项目创建成功!"));
}
/**
* 主函数,用于引导用户进行项目创建的配置选择
* 包含项目类型、编程语言、代码规范等配置项的交互式选择
*/
(async function main() {
const argv = yargs(hideBin(process.argv))
.option("name", {
alias: "n",
type: "string",
description: "项目名称",
coerce: (arg) => {
if (arg && !/^[a-zA-Z0-9_./-]+$/.test(arg)) {
throw new Error(
"项目路径只能包含英文字母、数字、下划线、连字符、点 (.) 和斜杠 (/)"
);
}
return arg;
},
})
.option("type", {
alias: "t",
type: "string",
description: "项目类型 (map 或 npm)",
default: "map",
})
.option("lang", {
alias: "l",
type: "string",
description: "开发语言 (ts 或 js)",
default: "ts",
})
.option("prettier", {
type: "boolean",
description: "配置代码规范工具",
default: false,
})
.option("i18n", {
type: "boolean",
description: "配置国际化",
default: false,
})
.option("side", {
type: "string",
description: "项目包含的端 (both, server 或 client)",
default: "both",
})
.option("dependentManner", {
type: "string",
description: "项目依赖方式 (npm 或 yarn 或 pnpm 或 bun)",
default: "npm",
})
.help()
.alias("help", "h").argv;
try {
if (argv.name) {
// 非交互式模式
const answers = {
npmPackage: {
value: argv.type === "npm" ? "神岛组件库" : "神岛地图项目",
},
languageType: {
value: argv.lang === "js" ? "JavaScript" : "TypeScript",
},
prettier: { value: argv.prettier ? "配置" : "跳过" },
i18n: { value: argv.i18n ? "配置" : "跳过" },
isServer: {
value:
argv.type === "map"
? {
server: "仅服务端",
client: "仅客户端",
both: "服务端和客户端",
}[argv.side] || "服务端和客户端"
: "",
},
dependentManner: {
value: argv.dependentManner,
},
};
const basepath = argv.name;
await createProject(basepath, answers);
} else {
const configWizard = new ConfigWizard({
showTemplates: false,
showAdvancedOptions: false,
});
const { answers, basepath, selectedTemplate } = await configWizard.run();
await createProject(basepath, answers, selectedTemplate);
}
} catch (error) {
await errorHandler.handleError(error, ErrorType.UNKNOWN, "项目创建", () => {
console.log(chalk.red("\n❌ 创建项目失败"));
console.log(chalk.dim("----------------------------------------"));
console.error(chalk.red(`错误详情: ${error.message}`));
});
process.exit(1);
}
})();