终端主流程派发
src/main.js
- 从终端读取用户输入的命令为字符串数组 ["sto","init","vue-manager","mymanager"]
- 将init命令派发给apply("init","vue-manager","mymanager")
- 核心代码
/**
* 定义命令速查表
* sto commands
* - config
* - init
*/
let actionMap = {
/* init命令配置 */
init: {
// init命令描述 终端:sto
description: "generate a new project from a template",
// init命令用法提示
usages: [`${cmdName} init templateName projectName`],
},
/* config命令配置 */
config: {
// config别名
alias: "cfg",
// config 命令描述
description: `config ${rcFile.name}`,
// config 用法提示
usages: [
`${cmdName} config set <k> <v>`,
`${cmdName} config get <k>`,
`${cmdName} config remove <k>`,
],
},
//other commands
};
/* 派发命令给指定的处理器函数 */
Object.keys(actionMap).forEach((action) => {
commander
.command(action)//接收终端命令 init/config
.description(actionMap[action].description)//添加命令描述
.alias(actionMap[action].alias) //添加别名
/* 定义命令的执行逻辑 */
.action(() => {
switch (action) {
case "config":
/* config真正的命令执行逻辑 */
// sto config set key value
// apply("config",key,value)
apply(action, ...process.argv.slice(3));
break;
case "init":
/* init真正的命令执行逻辑 */
// sto init templateName projectName
// apply("init",templateName projectName)
apply(action, ...process.argv.slice(3));
break;
default:
break;
}
});
});
命令派发器
src/index.js
- 对外导出apply函数
- apply函数会根据action的名字查询到具体的执行文件(例如init.js)
- 核心代码
/*
派发init命令给init.js
派发config命令给config.js
*/
// sto init vue-manager mymanager
let apply = (action, ...args) => {
// 找到init.js导出的处理器函数 调用之
// init("vue-manager","mymanager")
require(`./${action}`)(...args);
};
export default apply;
init命令执行器
src/init.js
- 从终端读取用户输入的工程描述和作者名字
- 调用init("vue-manager","mymanager")
- 从配置文件中的用户名对应的github代码仓库中下载
vue-manager模板代码,存储在mymanager目录 - 下载完毕后,根据用户的输入修改package.json文件
- 核心代码
/* init命令的执行逻辑 下载templateName对应的代码到本地 + 修改目录名称为projectName */
let init = async (templateName, projectName) => {
//项目不存在
if (!fs.existsSync(projectName)) {
//命令行询问器
inquirer.prompt([
// 要求用户输入项目描述 将来写入package.json中description字段
{
name: 'description',
message: 'Please enter the project description: '
},
{
name: 'author',
message: 'Please enter the author name: '
}
])
/* 用户输入完毕以后执行下载 */
.then(async (answer) => {
//下载模板 选择模板
//通过配置文件,获取模板信息
let loading = ora('🚀🚀 downloading template ...');
loading.start();
/* 下载templateName对应的代码到本地 + 修改目录名称为projectName */
downloadLocal(templateName, projectName)
// 下载完毕
.then(() => {
// 标记下载成功
loading.succeed();
// 准备写出myserver/package.json
const fileName = `${projectName}/package.json`;
// 如果myserver/package.json已经存在
if(fs.existsSync(fileName)){
// 读入本来数据
const data = fs.readFileSync(fileName).toString();
let json = JSON.parse(data);
/* 修改package.json中的数据 */
json.name = projectName;
json.author = answer.author;
json.description = answer.description;
// 修改项目文件夹中package.json文件 + 成功提示
fs.writeFileSync(fileName, JSON.stringify(json, null, '\t'), 'utf-8');
console.log(symbol.success, chalk.green('Project initialization finished!'));
}
}, () => {
loading.fail();
});
});
}
else {
//项目已经存在
console.log(symbol.error, chalk.red('The project already exists'));
}
}
module.exports = init;
下载逻辑
src/utils/get.js
- 调用
download-git-repo的下载方法执行下载 - 下载后的模板工程目录重命名为指定名称
- 核心代码
import { getAll } from "./rc";
import downloadGit from "download-git-repo";
import { templates } from "../../project.config.json";
export const downloadLocal = async (templateName, projectName) => {
let config = await getAll();
// baseUrl就是github.com 后续内容ouyangsuo/vue-manager
let api = `${config.registry}/${templateName}`;
console.log();
console.log(`开始下载[${templates[templateName]}] from`, api);
return new Promise((resolve, reject) => {
// 根据配置好的api地址从github上下载模板代码存储在projectName命名的路径下
downloadGit(api, projectName, (err) => {
if (err) {
reject(err);
}
resolve();
});
});
};