自定义脚手架

前端人每个人都应该有一个自己的脚手架, 不然每次新建项目也太麻烦了.

插件依赖

  • commander: 完整的 nodejs 命令行解决方案
  • download-git-repo: 用于 git 拉取代码
  • inquirer: 用户与命令行交互工具
  • ora: nodejs 命令行环境的 loading 效果, 和显示各种状态的图标
  • log-symbols: 提供带颜色的符号
  • chalk: 改变文字背景颜色
  • shelljs: 可以调用命令行工具

npm 发布

初始化项目

1
npm init -y

注册 npm 账号

走你—>

账号登录

如果设置了淘宝镜像, 要去除淘宝镜像

1
npm config set registry https://registry.npmjs.org

添加淘宝镜像: npm config set registry https://registry.npm.taobao.org

登录

1
npm login

发布

1
npm publish

全局安装golo-template-cli

1
npm i -g golo-template-cli

编辑基础命令

修改package.json文件, 添加命令

1
2
3
4
5
6
{
...,
"bin": {
"golo-template": "index.js"
}
}

根目录下新建index.js, 编辑

1
2
#!/usr/bin/env node
console.log("hello world");

将命令链接到全局

1
npm link

如果发现报错诸如:

1
npm ERR! EEXIST: file already exists, cmd shim 'C:\Users\ADMIN\AppData\Roaming\npm\node_modules\golo-template-cli\index.js' -> 'C:\Users\ADMIN\AppData\Roaming\npm\golo-template.cmd'

直接去C:\Users\ADMIN\AppData\Roaming\npm目录下将 golo-template 相关的三个文件删除再重新执行npm link

运行

1
2
npx golo-template
// 输出 hello world

编辑命令

编辑index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/env node
//你想要你的这个文件中的代码用什么可执行程序去运行它
//!/usr/bin/env node会去环境设置寻找node目录
const commander = require("commander");
const initAction = require("./commands/init");

// 查看版本号 也可以自定义命令查看版本号
commander
.version(require("./package.json").version)
.option("-v, --version", "查看版本号");

// 新建命令
commander
// .command('init <name>') // 定义子命令, <name>为必需参数 可在action的function中接收, 如需设置非必需参数, 可使用中括号
.command("init")
.option("-d, --dev", "获取开发版") // 配置参数, 简写和全写中使用,分隔
.description("创建项目") // 命令描述说明
.action(initAction);

// 利用commander解析命令行输入, 必须写在所有内容最后面
commander.parse(process.argv);

封装 clone 方法, 从 git 仓库拉取项目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const download = require("download-git-repo");
const symbols = require("log-symbols"); // 输出图标
const ora = require("ora"); // 用于输出loading
const chalk = require("chalk"); // 用于改变文字颜色
const clone = (remote, name, option) => {
const downSpinner = ora("正在下载模板...").start();
return new Promise((resolve, reject) => {
download(remote, name, option, (err) => {
if (err) {
downSpinner.fail();
console.log(symbols.error, chalk.red(err));
reject(err);
return;
}
downSpinner.succeed(chalk.green("模板下载成功!"));
resolve();
});
});
};
module.exports = clone;

封装 init 命令对应的执行逻辑

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
const fs = require("fs");
const shell = require("shelljs");
const symbols = require("log-symbols");
const inquirer = require("inquirer");
const gitConfig = require("../config/gitConfig");
const ora = require("ora"); // 用于输出loading
const chalk = require("chalk"); // 用于改变文字颜色
const clone = require("../utils/clone");

const questions = [
{
type: "input",
message: "请输入模板名称",
name: "name",
validate(val) {
if (!val) return "模板名不能为空!";
if (val.match(/[^A-Za-z0-9\u4e00-\u9fa5_-]/g))
return "模板名称包含非法字符,请重新输入";
if (fs.existsSync(val)) return "该文件夹已存在";
return true;
},
},
{
type: "list",
message: "请选择项目类型",
choices: ["simple-html", "vue-cli-h5"],
name: "type",
},
];

const initAction = async (option) => {
// 检查控制台是否可以运行git
if (!shell.which("git")) {
console.log(symbols.error, "对不起, git命令不可用!");
shell.exit(1);
}
// 通过inquirer获取到用户输入的内容
const answers = await inquirer.prompt(questions);
let confirm = await inquirer.prompt([
{
type: "confirm",
message: "是否创建?",
default: "Y",
name: "isConfirm",
},
]);
if (!confirm.isConfirm) return false;

const { type, name } = answers;
let branch = gitConfig[type].branch;
// 获取option, 确定模板分支
if (option.dev) branch = "develop";
const remote = gitConfig[type].remote;
// 下载模板
await clone(`direct:${remote}#${branch}`, name, { clone: true });
// 清理文件
const deleteDire = [
".git",
".gitignore",
"README.md",
"README.en.md",
"LICENSE",
];
const pwd = shell.pwd();
deleteDire.map((item) => shell.rm("-rf", pwd + `/${name}/${item}`));
// 进入目录
shell.cd(`./${name}`);
// 自动下载依赖
const installSpinner = ora("正在安装依赖...").start();
if (shell.exec("yarn install").code !== 0) {
console.log(symbols.warning, chalk.yellow("自动安装失败, 请手动安装"));
installSpinner.fail(); // 安装失败
shell.exit(1);
}
installSpinner.succeed(chalk.green("依赖安装成功"));
// 提示打开
console.log(chalk.gray("\n $ ") + chalk.blue(`cd ./${name}`));
console.log(chalk.gray(" $ ") + chalk.blue(`yarn serve`));
};

module.exports = initAction;