上一篇讲了一下cli的准备知识后,这一篇就到真正cli脚手架的核心文件
我们来重温一下,对cli需求分解一下,
用户层面:
需求:输入cli 命令 -> 终端选择 -> 输入基本信息 -> 文件生成
cli脚手架:
需求:接收命令 -> 进行命令获取和验证 -> 输出用户选择的指令 -> 实现指令功能 -> 下载模板(文件拷贝,生成) -> 安装依赖
创建目录文件
- template : cli生成的项目模板文件;
- .gitignore : git屏蔽文件,即不让git文件上传;
- cli.js : cli脚手架核心代码文件;
- package : 不解释啦……
- README : 不解释啦……
cli.js 核心介绍
commander:解析用户输入的命令
引入
//commande.js 可以自动的解析命令和参数,用于处理用户输入的命令。
const program = require('commander');
使用
当用户输入 sliao-cli -v //输出 ======Dark,sliao-cli====== version: 1.1.0
当用户输入 sliao-cli init test 就会进入action中;
inquirer 命令行交互
引入
// 设置环境变量的 文件头
const inquirer = require("inquirer");
使用
备注:此处demo展示就只列举了单项
当用户输入 sliao-cli init name 后,脚手架收到指令,解析然后提供配置参数输入
inquirer.then 进行逻辑书写;demo这里以生成html模板为例;
其他介绍
//chalk, 可以给终端的字体加上颜色
const chalk = require('chalk');
//log-symbols, 可以在终端上显示出 √ 或者 × 等的图标。
const symbols = require('log-symbols');
如 chalk 给终端上增加颜色,更加美观
脚手架代码实现
项目文件目录
脚手架相关配置在package.json
{
"name": "sliao-cli", //脚手架名称
"version": "1.1.0", //当前包版本
"description": "cli test ", //描述
"bin": "cli.js", //入口文件,脚手架核心入口文件
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
……
}
创建可执行文件
我们的可执行文件cli.js,当前为了方便直接放在更目录 此时我们要配置当前脚手架的执行环境,所以在cli文件的头部添加
#!/usr/bin/env node
该信息必须在头部,不能在其他顶部添加任何信息,否则会导致报错
开发核心文件cli.js
- inquirer 解析到用户操作后,对应执行脚手架核心文件;
- 此脚手架以生成html模板为例:
- 解析用户操作后执行拷贝文件,然后将模板生成对应文件夹,并生成对应模板文件;
直接上代码:
inquirer
.prompt([
{
type: "input",
name: "name",
message: "project name is ",
},
])
.then((answers) => {
// 模板目录
const tmlDir = path.join(__dirname, "templates");
// 目标目录
const destDir = process.cwd();
// 读取模板文件,将模板下的文件全部转换到目标目录
fs.readdir(tmlDir, (err, files) => {
if (err) throw err;
files.forEach((file) => {
// console.log(file);
// 通过模板引擎渲染文件
ejs.renderFile(path.join(tmlDir, file), answers, (error, result) => {
if (error) throw error;
// console.log(result)
// 将结果写入模板
fs.writeFileSync(path.join(destDir, file), result);
});
});
});
})
将我们的cli链接到全局,以便全局可以使用
- 进入项目文件
- 执行npm link
- 链接成功后即可使用全局命令
备注:使用命令调试方法 1.使用命令sliao-cli init name 2.使用node自带命令
到现在基本就完成了我们自定义的一个cli脚手架工程
执行
- 新建一个文件夹
- 进入文件夹,执行脚手架
- 将生成对应html模板
(截图为sliao-cli脚手架现有版本;欢迎使用sliao-cli脚手架;)
cli.js源码
#!/usr/bin/env node
// 设置环境变量的 文件头
const inquirer = require("inquirer");
const path = require("path");
const fs = require("fs");
const ejs = require("ejs");
//commande.js 可以自动的解析命令和参数,用于处理用户输入的命令。
const program = require('commander');
//chalk, 可以给终端的字体加上颜色
const chalk = require('chalk');
//log-symbols, 可以在终端上显示出 √ 或者 × 等的图标。
const symbols = require('log-symbols');
/**
* @description: program.version 调用该命令时 (如 sliao-cli -v) 会带出版本号:x.x.x
* @description: program.command 定义初始化命令 (如 sliao-cli init <项目名>)
* @description: program.action action 是执行command命令时发生的回调
* @param: node index.js init test == sliao-cli init test
* @returns: program.prase(process.argv)解析命令行中的参数,解析出name,并传入action回调
*/
program.version(chalk.green('======Dark,sliao-cli====== \n version: 1.1.0'), '-v, --version').
command('init <name>').
action(name => {
console.log(name)
//fs.existsSync 如果路径存在,则返回 true,否则返回 false
if (!fs.existsSync(name)) {
console.log(chalk.magentaBright('正在创建项目(Creating project)……'));
inquirer
.prompt([
{
type: "input",
name: "name",
message: "project name is ",
},
])
.then((answers) => {
// 模板目录
const tmlDir = path.join(__dirname, "templates");
// 目标目录
const destDir = process.cwd();
// 读取模板文件,将模板下的文件全部转换到目标目录
fs.readdir(tmlDir, (err, files) => {
if (err) throw err;
files.forEach((file) => {
// console.log(file);
// 通过模板引擎渲染文件
ejs.renderFile(path.join(tmlDir, file), answers, (error, result) => {
if (error) throw error;
// console.log(result)
// 将结果写入模板
fs.writeFileSync(path.join(destDir, file), result);
});
});
});
})
.catch((error) => {
// Something else went wrong
throw error;
});
} else {
console.log(symbols.error,chalk.red('项目依旧存在'));
}
})
program.parse(process.argv);
github源码欢迎Fork,让我们共同学习; github