txm-cli-demo
v1.0.0
Published
## 初始化
Downloads
2
Readme
脚手架实现过程
初始化
初始化一个项目目录并初始化package.json
mkdir txm-cli
cd txm-cli
yarn init -y
新建bin
目录,在bin
目录下创建入口文件cli.js
cli
应该必须要在入口文件声明
#!/usr/bin/env node
如果是 Linux 或者 macOS 系统下还需要修改此文件的读写权限为 755 chmod 755 cli.js
我们现在cli.js
文件中输出一段话
#!/usr/bin/env node
console.log('cli init')
然后配置package.json
文件中的bin
字段
{
"name": "txm-cli",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"bin": {
"txm": "bin/cli.js"
}
}
键代表我们要执行的cli
命令,值是入口文件的位置
执行yarn link
将命令连接到全局
执行bin
中配置的命令测试,例如:
txm
输出如下:
cli init
说明我们的基本配置就完成了,接下来就是完成具体的功能了
命令行参数设计
txm-cli -h|--help 查看使用帮助
txm-cli -v|--version 查看版本号
txm-cli list 列出所有可用模板
txm-cli init <template name> <project name> 基于指定的模板进行项目初始化
使用 commander 模块处理命令行
我们要做的就是
- 获取用户输入的参数
- 根据不同的参数生成不同的模板
在nodejs
中获取用户输入的命令可以使用process.argv
来获取,它拿到的是一个数组,然后数组里面的值是用户在命令行输入的参数,如果我们自己来判断这个参数还是比较麻烦的,所以这里借助 commander
这个模块来帮助我们处理参数
首先去安装commander
yarn add commander
commander
的使用也是比较简单的,使用教程
下面我们就来使用一下这个包
#!/usr/bin/env node
const { program } = require('commander');
program
.version('0.1.0')
program.parse(process.argv);
然后我们在命令行中输入
txm -V
输出结果:
0.1.0
这就说明这个包可以正常使用了,接下来就来配置一下我们自己的命令
因为help
命令它自己就有,所以我们不用配置,我们先来配置一下init
命令
// 配置init命令
program
.command('init <template> <project>') // 尖括号代表必输项,第一个参数是模板名称,第二个参数是项目名称
.description('init project...') // 执行命令时的描述信息
.action(function (templateName, projectName) { // 接收到用户输入的参数后要做的事情
// 根据模板名称下载对应的模板到本地并起名为 projectName
console.log(templateName, projectName)
})
执行一下
txm init webpack my-project
输出结果:
webpack my-project
init
命令配置好了之后我们先去配置一下list
命令,具体的实现我们等下在去做
// 配置 list 命令
program
.command('list')
.description('list all templates')
.action(() => {
console.log(`sample sample模板`)
console.log(`webpack webpack模板`)
console.log(`vue vue模板`)
console.log(`react react模板`)
})
我们简单的配置一下,具体的一会儿再来实现
执行
txm list
输出结果:
sample sample模板
webpack webpack模板
vue vue模板
react react模板
到这里我们的命令就配置好了
准备模板
在github
上创建三个仓库,一个仓库里面放vue
的基础模板,一个仓库放react
的基础模板,一个就准备一个简单的项目结构,然后我们修改一下我们的list
命令
三个模板仓库的地址
https://github.com/tangxinming0310/txm-vue-tempalte
https://github.com/tangxinming0310/txm-react-template
https://github.com/tangxinming0310/txm-sample-tempalte
我们在cli.js
中去定义我们的模板仓库
const templates = {
'sample': {
url: 'https://github.com/tangxinming0310/txm-sample-template',
desc: 'sample-template'
},
'react': {
url: 'https://github.com/tangxinming0310/txm-react-template',
desc: 'react-template'
},
'vue': {
url: 'https://github.com/tangxinming0310/txm-vue-tempalte',
desc: 'vue-template'
}
}
然后在list
命令中去修改一下
// 配置 list 命令
program
.command('list')
.description('list all templates')
.action(() => {
Object.keys(templates).forEach(key => {
console.log(`${key} ${templates[key].desc}`)
})
})
执行:
txm list
输出结果:
sample sample-template
react react-template
vue vue-template
下载模板
模板准好了之后,我们就需要根据用户的输入然后去获取模板地址并下载对应的模板
下载模板我们需要借助一个 download-git-repo
的库
先安装这个库
yarn add download-git-repo
使用方式:
// 第一参数是下载地址 规则为 => [github]:[账户名]/[仓库名]
// 第二参数是项目的名称
download(downloadUrl, projectName, { clone: true }, (err) => {
if (err) {
console.log(`download ${templateName} template failed`)
} else {
console.log('download success')
}
})
所以这里我们对templates
添加一个下载地址
const templates = {
'sample': {
url: 'https://github.com/tangxinming0310/txm-sample-template',
downloadUrl: 'https://github.com:tangxinming0310/txm-sample-template',
desc: 'sample-template'
},
'react': {
url: 'https://github.com/tangxinming0310/txm-react-template',
downloadUrl: 'https://github.com:tangxinming0310/txm-react-template',
desc: 'react-template'
},
'vue': {
url: 'https://github.com/tangxinming0310/txm-vue-tempalte',
downloadUrl: 'https://github.com:tangxinming0310/txm-vue-tempalte',
desc: 'vue-template'
}
}
然后去修改我们的init
命令
// 配置 init 命令
program
.command('init <template> <project>') // 尖括号代表必输项,第一个参数是模板名称,第二个参数是项目名称
.description('init project...') // 执行命令时的描述信息
.action(function (templateName, projectName) { // 接收到用户输入的参数后要做的事情
// 根据模板名称下载对应的模板到本地并起名为 projectName
// 根据用户输入获取对应的模板地址
const { downloadUrl } = templates[templateName]
// 下载模板
download(downloadUrl, projectName, { clone: true }, (err) => {
if (err) {
console.log(`download ${templateName} template failed`)
} else {
console.log('download success')
}
})
})
在命令行执行:
txm vue vue-demo
结果:可以看到在当前目录下生成了一个 vue-demo 的文件夹,里面就是我们仓库里面的模板文件
命令行交互
模板下载好了之后我们在增加一下命令行交互来增强用户体验,比如说package.json
文件中的一些信息我们可以让用户自己来填写,例如author
,name
等
这里我们就需要使用到模板引擎了
我们先对仓库中的package.json
文件做一些改写,我们把name
、author
、description
这个三个字段改写成模板引擎的方式
"name": "<%= name %>",
"author": "<%= author %>",
"description": "<%= description %>"
然后我们使用ejs
作为模板引擎
yarn add ejs
命令行交互这里需要用到inquirer
库,先安装
yarn add inquirer
然后我们去引入几个模块
const fs = require('fs')
const path = require('path')
const inquirer = require('inquirer')
const ejs = require('ejs')
因为我们需要读取package.json
文件,所以需要用到fs
和path
两个库
然后我们在项目模板下载完成后
- 向用户发起询问
- 根据用户的回答使用模板引擎把用户的值解析到
package.json
中 - 解析完成后,把解析之后结果重新写入
package.json
根据这个步骤我们去修改一下我们的init
命令
// 配置 init 命令
program
.command('init <template> <project>') // 尖括号代表必输项,第一个参数是模板名称,第二个参数是项目名称
.description('init project...') // 执行命令时的描述信息
.action(function (templateName, projectName) { // 接收到用户输入的参数后要做的事情
// 根据模板名称下载对应的模板到本地并起名为 projectName
// 根据用户输入获取对应的模板地址
const { downloadUrl } = templates[templateName]
download(downloadUrl, projectName, { clone: true }, (err) => {
if (err) {
return console.log(`download ${templateName} template failed`)
}
// 发起命令行交互
inquirer.prompt([
{
type: 'input',
name: 'name',
message: 'Project name?',
default: projectName
},
{
type: 'input',
name: 'description',
message: 'Project description?'
},
{
type: 'input',
name: 'author',
message: 'Project author?'
}
])
.then(answers => {
// package.json 文件的路径
const packagePath = path.join(projectName, 'package.json');
// 使用模板引擎把用户的值解析到 package.json 中
ejs.renderFile(packagePath, answers, (err, result) => {
if (err) throw err
// 解析完成后,把解析之后结果重新写入 package.json
fs.writeFileSync(packagePath, result)
console.log(`${templateName} template init success`)
})
})
})
})
然后我们去测试一下
txm vue vue-demo
然后可以看到命令行会发出一些问题交互,我们输入信息后,打开vue-demo
文件夹,查看package.json
文件,可以看到其中的表达式已经全部被替换成我们输入的信息了
增加下载动画
现在我们的cli
工具有了,但是在下载模板的时候是感知不到的,这一点体验不是很好,我们去增加一个下载的loading
动画,借助ora
这个库来实现
安装
yarn add ora
基本的使用方式
const ora = require('ora')
const spinner = ora('downloading...')
spinner.start()
spinner.fail() // 下载失败
spinner.succeed() // 下载成功
增加文字颜色和小图标
然后我们可以通过chalk
这个库为打印的信息加上样式,比如成功为绿色,失败为红色,可以使得我们的终端效果更加友好
yarn add chalk
基本使用,它有很多种颜色,我们需要什么颜色就使用什么颜色就好了
console.log(chalk.red(err))
console.log(chalk.green('success'))
使用log-symbols
来增加小图标
yarn add log-symbols
使用方式就是在输出的第一个位置直接使用他对应的图标就好了
console.log(logSymbols.success, chalk.green('success'))
完整的cli代码
请查看bin
目录下cli.js
文件