UNPKG

@ky-cli/create

Version:

ky-cli 创建项目包

292 lines (279 loc) 7.47 kB
"use strict"; const fs = require("fs"); const path = require("path"); const inquirer = require("inquirer"); const fsExtra = require("fs-extra"); const semver = require("semver"); const userHome = require("user-home"); const glob = require("glob"); const ejs = require("ejs"); const validNpmName = require("validate-npm-package-name"); const Command = require("@ky-cli/command"); const log = require("@ky-cli/log"); const Mongdb = require("@ky-cli/handle-mongdb"); const { DEFAULT_CLI_HOME, MONGDBURL, MONGDBNAME } = require("@ky-cli/global-config"); const { spinnerStart, sleep, execAsync, toLowerCase } = require("@ky-cli/utils"); const Package = require("@ky-cli/package"); const SetSubProject = require("./setSubProject"); const mongdb = new Mongdb(MONGDBURL, MONGDBNAME); class InitCommand extends Command { // 1.保存项目名 + 保存force状态 init() { this.projectName = this._argv[0]; this.force = !!this._cmd.force; log.debug("projectName", this.projectName); log.debug("force", this.force); } // 2.执行init命令 async exec() { try { // 1.准备阶段 this.projectInfo = await this.prepare(); if (this.projectInfo) { // 2.下载模版 await this.downloadTemplate(); // 3.安装模版 await this.installTemplate(); } } catch (e) { log.error(e.message); if (process.env.LOG_LEVEL === "debug") { console.error(e); } } } // 2-1.准备阶段返回项目信息 async prepare() { this.templateConfig = await mongdb.query("project_info"); mongdb.close(); return this.getProjectInfo(); } async getProjectInfo() { let projectInfo = await inquirer.prompt([ { type: "list", name: "template", message: "请选择您需要创建的项目模版", default: "@ky-template/common-single", choices: this.templateConfig.map(e => ({ name: e.name, value: e.npmName })) }, { type: "input", name: "projectName", message: "请输入项目名称", default: this.projectName || "ky-cli-project", validate: v => validNpmName(v).validForNewPackages }, { type: "number", name: "projectPort", message: "请输入当前子项目端口号", default: 7001, validate: v => { const ssp = new SetSubProject(); return !ssp .getChildMess() .map(e => Number(e.port)) .includes(v); }, when: answer => answer.template === "@ky-template/microservice-child" } ]); projectInfo.packageName = toLowerCase(projectInfo.projectName); projectInfo.projectVersion = "1.0.0"; return { ...projectInfo }; } async downloadTemplate() { this.templateInfo = this.templateConfig.find( e => e.npmName === this.projectInfo.template ); if (this.templateInfo) { const targetPath = path.resolve(userHome, DEFAULT_CLI_HOME, "template"); const storeDir = path.resolve(targetPath, "node_modules"); const templateNpm = new Package({ targetPath, storeDir, name: this.templateInfo.npmName, version: this.templateInfo.version }); // 模版文件存在那么更新对应模版,否则进行模版安装 if (await templateNpm.exists()) { const spinner = spinnerStart("正在进行模版更新安装"); console.log(""); try { await sleep(); await templateNpm.update(); this.templateNpm = templateNpm; } catch (e) { throw e; } finally { spinner.stop(true); if (await templateNpm.exists()) { log.success("模版更新成功!"); } } } else { const spinner = spinnerStart("正在进行模版下载安装"); console.log(""); try { await sleep(); await templateNpm.install(); this.templateNpm = templateNpm; log.success("模版下载成功!"); } catch (e) { throw e; } finally { spinner.stop(true); if (await templateNpm.exists()) { log.success("模版下载成功!"); } } } } } async installTemplate() { const targetPath = this.getTargetPath(); if (!this.isCwdEmpty(targetPath)) { const isEmptyDir = await this.emptyDir(targetPath); if (!isEmptyDir) return false; } const spinner = spinnerStart("正在进行代码本地复制......"); try { // 1.判断当前执行目录是否为空且判断当前 const templatePath = path.resolve( this.templateNpm.getCacheFilePath(this.templateInfo.version), "template" ); await fsExtra.ensureDirSync(templatePath); await fsExtra.copySync(templatePath, targetPath); } catch (e) { throw new Error(e.message); } finally { spinner.stop(); } const ignore = ["**/node_modules/**", ...(this.templateInfo.ignore || [])]; await this.ejsRender({ ignore }); const { installCommand, startCommand } = this.templateInfo; if (this.projectInfo.template === "@ky-template/microservice-child") { const setSubProject = new SetSubProject(); setSubProject.setRouteContent(); setSubProject.setAppsContent(); } installCommand && (await this.execCommand(installCommand, "项目npm包初始化完成!")); // await this.execCommand("npm run eslint", "项目格式化完成"); startCommand && (await this.execCommand(startCommand, "项目启动成功!")); } getTargetPath() { let targetPath = process.cwd(); switch (this.projectInfo.template) { case "@ky-template/microservice-child": targetPath = path.resolve( process.cwd(), `packages/${this.projectInfo.projectName}` ); break; } return targetPath; } async emptyDir(localPath) { let force = false; if (!this.force) { force = ( await inquirer.prompt([ { type: "confirm", name: "force", message: "该目录下存在文件或者目录,是否进行强制覆盖", default: false } ]) ).force; if (!force) { return false; } } if (force || this.force) { const spinner = spinnerStart("本地文件清空中......"); // 清空当前目录 fsExtra.emptyDirSync(localPath); spinner.stop(true); } return true; } async ejsRender(options) { const dir = process.cwd(); const projectInfo = this.projectInfo; return new Promise((resolve, reject) => { glob( "**", { cwd: dir, ignore: options.ignore || "", nodir: true }, function (err, files) { if (err) { reject(err); } Promise.all( files.map(file => { const filePath = path.join(dir, file); return new Promise((resolve1, reject1) => { ejs.renderFile(filePath, projectInfo, {}, (err, result) => { if (err) { reject1(err); } else { fsExtra.writeFileSync(filePath, result); resolve1(result); } }); }); }) ) .then(() => { resolve(); }) .catch(err => { reject(err); }); } ); }); } async execCommand(commands, msg) { const [command, ...args] = commands.split(" "); const ret = await execAsync(command, args, { cwd: process.cwd(), stdio: "inherit" }); if (ret !== 0) { throw new Error(msg + "失败!"); } log.success(msg); } isCwdEmpty(localPath) { fsExtra.ensureDirSync(localPath); const fileList = fs .readdirSync(localPath) .filter(file => !file.startsWith(".") && !file.includes("node_modules")); return fileList.length === 0; } } function init(argv) { return new InitCommand(argv); } module.exports = init; module.exports.InitCommand = InitCommand;