背景
最近来了几个新同事,由于没有及时沟通,导致好几个同事在开发新项目的时候自己去搭建或者网上找了模板,去开发新的项目。然后我就想能不能像 vue-cli 一样 通过 vue create xxx 一样自动生成一个项目模版
思考
针对现有的业务例如我们有 钉钉 h5、pc、electorn 等等, 如何用一套开发环境感觉太冗余了,所以大概分三个模版。然后模版维护在哪也是一个问题,现在目前有两种方案第一种像 vue 一样维护到远端,每次 create 的时候去拉最新的代码生成模版。第二种就是维护到自己的工程下面,但是这样每次改动都要发新版本太过麻烦。所以思来想去维护到远端,我这里是维护到公司的 giatlab 上面。
预期
- npm i my-cli -g
- my-cli init myapp 将展示如下选项
- 🌰如我们选择 spa 项目以后会填一些基本信息,然后去执行下载操作
4. 然后根据所填信息针对模版开启一些配置,写入一些信息在这里我们会将这两项写入 package.json 里面
- 最终结果如下
同时在当前目录下生成一个叫 myapp 的模版
准备一些库
chalk --node终端样式库
const chalk = require('chalk');
// 输出蓝色的MCC
console.log(chalk.blue('MCC'));
commander --node.js命令行界面的方案
var program = require('commander');
program
.version('0.1.0')
inquirer.js --用户与命令行交互的工具
const promptList = [{
type: 'input',
message: '设置一个用户名:',
name: 'name',
default: "test_user" // 默认值
},{
type: 'input',
message: '请输入手机号:',
name: 'phone',
validate: function(val) {
if(val.match(/\d{11}/g)) { // 校验位数
return val;
}
return "请输入11位数字";
}
}];
fs-extra 文件操作相关工具库
fs-extra模块是系统fs模块的扩展,提供了更多便利的 API,并继承了fs模块的 API
var fs = require('fs-extra');
fs.copy('/tmp/myfile', '/tmp/mynewfile', function (err) {
if (err) return console.error(err);
ora 终端 loading 库
figlet 输出一些特殊的文字,这些文字只包含 ANSI 对应的字符
思路
实现
#!/usr/bin/env node
const fs = require("fs");
const { program } = require("commander");
const inquirer = require("inquirer");
const ora = require("ora");
const chalk = require("chalk");
const symbols = require("log-symbols");
const figlet = require("figlet");
const sh = require("../src/shell");
const config = require("../src/config");
const getRepoName = require("../src/getRepoName");
const buildProject = require("../src/buildProject");
const fileName = process.argv[3];
const filePath = process.cwd();
console.log(fileName, filePath, "aa");
program
.version("0.0.1", "-v, --version")
.command("init <name>")
.action((name) => {
if (!fs.existsSync(name)) {
inquirer
.prompt([config.projectList, config.description, config.author])
.then(async (answers) => {
let spinner = ora("正在生成项目中...");
spinner.start();
try {
//获取要下载的仓库地址
const url = config.repo[answers.projectType];
if (!url) {
spinner.fail();
return console.log(
symbols.error,
chalk.green("模版正在开发中--")
);
}
const repoName = getRepoName(url);
// 获取下载下来的仓库名字
spinner.text = "正在下载新的的模版";
// 下载之前无脑删除
await sh(`rm -rf ${repoName}`);
// 然后开始下载模版
await sh("git clone " + url);
// 开始构建新的目录
buildProject({
...answers,
fileName,
filePath,
repoName,
});
// 正在生成项目
spinner.text = "生成完成";
spinner.succeed();
// 生成图标
figlet("REACT CLI", function (err, data) {
if (err) {
console.log("Something went wrong...");
console.dir(err);
return;
}
console.log(data);
});
// 转移文件夹
} catch (error) {
spinner.fail();
console.log(symbols.error, chalk.red(error));
}
});
} else {
// 错误提示项目已存在,避免覆盖原有项目
console.log(symbols.error, chalk.red("项目已存在"));
}
});
program.parse(process.argv);
第一行一定要加这句话
#!/usr/bin/env node
/usr/bin/env就是告诉系统可以在PATH目录中查找。 所以配置#!/usr/bin/env node, 就是解决了不同的用户node路径不同的问题,可以让系统动态的去查找node来执行你的脚本文件
目录
核心文件放在 bin 下面, 同时在 package.json 里面加上如下的命令
"bin": {
"my-cli": "bin/index.js"
}
最后
代码放在这里