需求背景:bff接口服务,定义参数类型以及返回类型。前端ts项目如果能讲定义的类型引用过来,就不需要重复定义类型,而且可以随着接口定义而改动,提高开发效率。
功能:运行该 cli 命令后,会拉取指定的bff项目,然后将克隆下来的项目里一个声明类型的目录拷贝到对应 cli 项目下,最后删除克隆的项目。
1、先编写node脚本
(1)创建文件夹 bff-types-cli。
(2)在改文件夹下创建 index.js。
console.log('bff-types-cli')
(3)此时,运行 node .\index.js。
// bff-types-cli
2、脚本制作cli命令行
(1) 新建一个package.json 文件
npm init -y
(2)添加package.json的bin字段
{
"main": "index.js",
"bin":{
"bff-types-cli":"index.js"
},
}
(3)index.js文件顶部声明执行环境。
#!/usr/bin/env node
console.log('bff-types-cli')
// 添加 #!/usr/bin/env node 或者 #!/usr/bin/node ,这是告诉系统,下面这个脚本,使用nodejs来执行。
// #!/usr/bin/env node 的意思是让系统自己去找node的执行程序。
// #!/usr/bin/node 的意思是,明确告诉系统,node的执行程序在路径为 /usr/bin/node 。
(4)执行 npm link。
在当前package.json目录下,打开命令行工具,执行 npm link ,将当前的代码在npm全局目录下留个快捷方式。相当于全局安装了 bff-types-cli 这个脚手架了。
(5)在终端执行 bff-types-cli 命令,执行index.js中的脚本。
// bff-types-cli
3、编写查看版本-v指令
(1)安装 commander 库,node.js 命令行界面的完整解决方案。
yarn add commander
(2)编写index.js 文件
console.log('bff-types-cli')
const program = require("commander");
// 参数'-v, --version', 作用: -v --version 指令 替换 -V
program.version(require('./package.json').version, '-v, --version');
program.parse(process.argv);
(3)执行 bff-types-cli -v 或者 bff-types-cli --version 命令。
// bff-types-cli
// 1.0.0
4、编写 -h 指令的提示信息
(1)执行 bff-types-cli -h 命令
// 下面是默认的提示信息
bff-types-cli
Usage: index [options]
Options:
-v, --version output the version number
-h, --help display help for command
(2)添加一个 options 选项 (可供后面定义的指令使用该选项,获取选项的属性 program.xxx )
program.version(require('./package.json').version, '-v, --version');
program.option('-i, --integer <n>', 'An integer argument')
(3)执行 bff-types-cli -h 命令
bff-types-cli
Usage: index [options]
Options:
-v, --version output the version number
-i, --integer <n> An integer argument
-h, --help display help for command
(4)添加 other 提示
program.on('--help', function(){
console.log('')
console.log('Other:');
console.log(' $ bff-types-cli --help');
console.log(' $ bff-types-cli -h');
console.log(' $ bff-types-cli -v');
console.log(' $ bff-types-cli --interger 1');
});
(5)执行 bff-types-cli -h 命令
bff-types-cli
Usage: index [options]
Options:
-v, --version output the version number
-i, --integer <n> An integer argument
-h, --help display help for command
Other:
$ bff-types-cli --help
$ bff-types-cli -h
$ bff-types-cli -v
$ bff-types-cli --interger 1
5、编写功能
(1)安装依赖包
// chalk 和 ora 需要指定版本。因为需要commonjs的格式
yarn add chalk@4.1.2 ora@5.4.1 clear commander download-git-repo figlet--save-dev
(2)创建文件,bff-types-cli/lib/creatTypeFile.js。
const { promisify } = require("util");
const figlet = promisify(require("figlet"));
const clear = require("clear");
const chalk = promisify(require("chalk"));
const log = (content) => console.log(chalk.green(content));
const ora = require("ora");
const fs = require("fs");
// const fsPromises = require('fs').promises;
const path = require("path");
const download = promisify(require("download-git-repo"));
const projectRelation = require('../util/data');
const cloneProject = async (url, fileName, typesFile) => {
// 克隆项目
const process = ora(`下载中...`);
process.start();
await download(url, fileName, { clone: true }, async(err) => {
if(err) {
process.fail(`可能已经存在,${err}`)
} else {
process.succeed('下载成功');
const typesLoading = ora(`生成types文件中...`);
typesLoading.start();
copyDirectory(`${fileName}/src/enum`, typesFile); // 复制类型文件到指定目录
typesLoading.succeed('types类型目录生成成功!');
rmDirDeepSync(fileName);
setTimeout(() => {
clearFile(fileName);
}, 500);
}
});
};
const clearFile = (fileName) => {
if(fs.existsSync(fileName)) {
fs.rmdirSync(fileName, { recursive: true })
}
}
function rmDirDeepSync(dir) {
let statObj = fs.statSync(dir);
if (statObj.isDirectory()) {
let dirs = fs.readdirSync(dir);
for(let i = 0; i < dirs.length; i++ ) {
rmDirDeepSync(path.join(dir, dirs[i]))
}
fs.rmdirSync(dir, { recursive: true });
} else {
fs.unlinkSync(dir);
}
}
function copyDirectory(src, dest) {
if (fs.existsSync(dest) == false) {
fs.mkdirSync(dest);
}
if (fs.existsSync(src) == false) {
return false;
}
// 拷贝新的内容进去
let dirs = fs.readdirSync(src);
dirs.forEach(function(item){
let item_path = path.join(src, item);
let temp = fs.statSync(item_path);
if (temp.isFile()) { // 是文件
// console.log("Item Is File:" + item);
fs.copyFileSync(item_path, path.join(dest, item));
// fsPromises.copyFile(item_path, path.join(dest, item))
} else if (temp.isDirectory()){ // 是目录
// console.log("Item Is Directory:" + item);
copyDirectory(item_path, path.join(dest, item));
}
});
}
module.exports = async (name) => {
// 清楚日志
clear();
const data = await figlet("bff-types-cli");
输出日志
log(data);
// 暂时用 bff-marketing-app,后面通过命令传进来
const bffProjectName = 'bff-marketing-app';
const typesFile ='bff-types';
if(!projectRelation[bffProjectName]) {
console.log('Error: bff项目不存在!')
return;
}
const url = `${projectRelation[bffProjectName].url}#${projectRelation[bffProjectName].branch}`;
clearFile(bffProjectName); // 删除bff项目
clearFile(typesFile); // 删除类型文件夹
cloneProject(url, bffProjectName, typesFile); // 克隆bff项目
};
(3)添加运行的文件
program.action(require("./lib/creatTypeFile")); // 这里执行的文件所在
(4)运行 bff-types-cli