这是系列文章 前端脚手架实现] 的第二篇,在上文脚手架Yue-cli的实现01-commander模块中,介绍了如何让Yue-cli在用户的终端中可用,并通过commander 模块提供了help、version以及 create 等基本指令,本文将介绍脚手架中Yue-cli create xxx命令来初始化项目时内部的处理过程和实现方案。

安装axios模块,该模块用来发送网络请求获取模板和对应的版本列表,该模板用来初始化 Vue 项目。

1
npm install axios

安装ora模块,该模块的主要作用是在终端中显示提示消息。

1
npm install ora

安装inquirer询问者模块,该模块展示根据拉取的模板和版本号列表,并让用户选择。

1
npm install inquirer

先修改 main.js 文件中action中的实现方式,这样的话当执行Yue-cli create xx指令的时候会加载并执行对应文件中的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/* 列出 main.js 文件对命令执行的映射处理 */
const program = require("commander")

/* 组织映射结构 */
const actions = {
create: { // 项目创建(初始化)指令
description: 'create project with Yue-cli',
alias: 'c',
examples: [
'Yue-cli create <project-name>',
],
},
config: { // 设置项目配置文件指令
description: 'config info',
alias: 'conf',
examples: [
'Yue-cli config get <k>',
'Yue-cli config set <k> <v>',
],
},
'*': {
description: 'command not found',
alias: '',
examples: [],
},
};

Object.keys(actions).forEach((action) => {
program
/* 命名的名称 */
.command(action)
/* 命名的别名 */
.alias(actions[action].alias)
/* 命令的描述信息 */
.description(actions[action].description)
/* 命令的任务(功能) */
.action(() => { // 动作
console.log(`执行 action->`, action);
console.log(process.argv);

/* 示例:Yue-cli create xxx */
/* 命令的参数分布如下
[ '/usr/local/bin/node',
'/usr/local/bin/Yue-cli',
'create',
'xxx'
] */
require(path.resolve(__dirname, action))(...process.argv.slice(3));
});
});

在项目的src目录中新创建 create.js 文件,这样当执行Yue-cli create xxx指令的时候会自动加载并执行create.js文件中的代码,当执行config xxx指令的时候会自动加载并执行config.js文件中的代码。这里主要讨论当执行create指令的时候,命令行工具的内部应该处理哪些任务,下面列出代码的主要处理过程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/* 列出 create.js 文件中的主要代码 */

/* 1.导入模块 */
const axios = require('axios');
const ora = require('ora');
const fs = require('fs');
const inquirer = require('inquirer');

/* 2.封装函数获取存放模板信息的数据 */
async function getRepositoryList() {
const { data } = await axios.get("https://api.github.com/orgs/Yong-template/repos");
return data;
}

/* 3.封装函数获取对比仓库模板文件的版本列表 */
const getTagList = async(repo) => {
const {data} =await axios.get(`https://api.github.com/repos/Yong-template/${repo}/tags`);
return data;
};

/* 4.封装函数显示提示信息... */
const loading = (fn, message) => async(...args) => {
const spinner = ora(message);
spinner.start();
const result = await fn(...args);
spinner.succeed();
return result;
};

module.exports = async(projectName) => {

/* 处理模板信息 */
let repoList = await loading(getRepositoryList, "fetching template ...")();

/* 选择模板 */
const { repo } = await inquirer.prompt({
name: "repo",
type: "list",
message: "please choice a template to create project !",
choices: repoList.map(item => item.name)
})

/* 处理版本信息 */
let tagList = await loading(getTagList, "fetching tags ...")(repo);

/* 选择对应的版本 */
const { tag } = await inquirer.prompt({
name: 'tag',
type: 'list',
message: 'please choices tags to create project',
choices: tagList.map(item => item.name),
});

/* 打印选定的模板和版本信息 */
console.log("repo->",repo,"tag->",tag);
};

列出简单列出脚手架指令Yue-cli create app的执行情况。

1
2
3
4
5
6
7
8
9
10
11
wendingding$ Yue-cli create app
执行 action-> create
[ '/usr/local/bin/node',
'/usr/local/bin/Yue-cli',
'create',
'app' ]
✔ fetching template ...
? please choice a template to create project ! vue-simple-template
✔ fetching tags ...
? please choices tags to create project (Use arrow keys)
❯ v2.0.0