开发Node CLI构建微信小程序脚手架的示例(2)

然后需要注意的是, commander 支持 Git 风格的子命令处理,可以根据子命令自动引导到以特定格式命名的命令执行文件,文件名的格式是 [command]-[subcommand] ,例如:

modoo-script init => modoo-script-init modoo-script build => modoo-script-build

所以为了实现 init 命令,可以直接在 bin 文件目录下添加 modoo-script-init.js

#!/usr/bin/env node const { program } = require("commander"); program .option("--name [name]", "项目名称") .option("--description [description]", "项目介绍") .option("--framework", "脚手架框架") .parse(process.argv); const args = program.args; // 获取命令参数 const { name, description, framework } = program; const projectName = args[0] || name; ......

用户交互

获取了命令参数后,根据参数转到用户交互界面,这里使用的是 inquirer 来处理命令行交互, 用法很简单

const inquirer = require('inquirer') if (typeof conf.description !== 'string') { prompts.push({ type: 'input', name: 'description', message: '请输入项目介绍!' }) } ...... inquirer.prompt(prompts).then(answers => { // 整合配置 this.conf = Object.assign(this.conf, answers); })

远程模块

这里较为折腾,一开始说了,我把模版作为 npm包 ,具体查找,下载的过程如下

npm search 查找相应的模版 npm 包

在用户选择框架后对应所需的包,获取它的详细信息,主要是 tarball

用户输入完后,下载 tarball 到项目目录,并修改 .json 文件配置

部分代码如图所示

// 一 npm search 查找相应的模版 npm 包 const { execSync } = require("child_process"); module.exports = () => { let list = []; try { const listJSON = execSync( "npm search --json --registry @modoo/modoo-template" ); list = JSON.parse(listJSON); } catch (error) {} return Promise.resolve(list); };

// 二 返回 npm 数据 const pkg = require("package-json"); const chalk = require("chalk"); const logSymbols = require("log-symbols"); exports.getBoilerplateMeta = framework => { log( logSymbols.info, chalk.cyan(`您已选择 ${framework} 远程模版, 正在查询该模版...`) ); return pkg(framework, { fullMetadata: true }).then(metadata => { const { dist: { tarball }, version, name, keywords } = metadata; log( logSymbols.success, chalk.green(`已为您找到 ${framework} 远程模版, 请输入配置信息`) ); return { tarball, version, keywords, name }; }); };

// 三 下载 npm 包 const got = require("got"); const tar = require("tar"); const ora = require("ora"); const spinner = ora( chalk.cyan(`正在下载 ${framework} 远程模板仓库...`) ).start(); const stream = await got.stream(tarball); fs.mkdirSync(proPath); const tarOpts = { strip: 1, C: proPath }; // 管道流传输下载文件到当前目录 stream.pipe(tar.x(tarOpts)).on("close", () => { spinner.succeed(chalk.green("下载远程模块完成!")); ...... })

// 四 遍历文件修改配置 const fs = require("fs-extra"); readFiles( proPath, { ignore: [ ".{pandora,git,idea,vscode,DS_Store}/**/*", "{scripts,dist,node_modules}/**/*", "**/*.{png,jpg,jpeg,gif,bmp,webp}" ], gitignore: true }, ({ path, content }) => { fs.createWriteStream(path).end(template(content, inject)); } ); // 递归读文件 exports.readFiles = (dir, options, done) => { if (!fs.existsSync(dir)) { throw new Error(`The file ${dir} does not exist.`); } if (typeof options === "function") { done = options; options = {}; } options = Object.assign( {}, { cwd: dir, dot: true, absolute: true, onlyFiles: true }, options ); const files = globby.sync("**/**", options); files.forEach(file => { done({ path: file, content: fs.readFileSync(file, { encoding: "utf8" }) }); }); }; // 配置替换 exports.template = (content = "", inject) => { return content.replace(/@{([^}]+)}/gi, (m, key) => { return inject[key.trim()]; }); };

下载依赖

下载完毕并且修改完配置后, 默认执行 git init + 根据环境( yarn / npm / cnpm )安装依赖,这个就很简单了

const { exec } = require("child_process"); const ora = require("ora"); const chalk = require("chalk"); // proPath 项目目录 process.chdir(proPath); // git init const gitInitSpinner = ora( `cd ${chalk.cyan.bold(projectName)}, 执行 ${chalk.cyan.bold("git init")}` ).start(); const gitInit = exec("git init"); gitInit.on("close", code => { if (code === 0) { gitInitSpinner.color = "green"; gitInitSpinner.succeed(gitInit.stdout.read()); } else { gitInitSpinner.color = "red"; gitInitSpinner.fail(gitInit.stderr.read()); } }); // install let command = ""; if (shouldUseYarn()) { command = "yarn"; } else if (shouldUseCnpm()) { command = "cnpm install"; } else { command = "npm install"; } log(" ".padEnd(2, "\n")); const installSpinner = ora( `执行安装项目依赖 ${chalk.cyan.bold(command)}, 需要一会儿...` ).start(); exec(command, (error, stdout, stderr) => { if (error) { installSpinner.color = "red"; installSpinner.fail(chalk.red("安装项目依赖失败,请自行重新安装!")); console.log(error); } else { installSpinner.color = "green"; installSpinner.succeed("安装成功"); log(`${stderr}${stdout}`); } });

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/b3b3bf75ba5dcb2d48295636b252d571.html