思维导图:
1、初始化项目
mkdir auto-cli
cd auto-cli
npm init -y
npm i commander download-git-repo ora handlebars figlet clear chalk open watch -s
2、新建CLI命令文件: 新建auto-cli/bin/kkb.js命令文件
#!/us/bin/env node // 指定解析环境为node
console.log('auto-cli....')
const program = require('commander') //命令行工具
program.version(require('../package.json').version) // 或直接写 '1.0.1'
program
.command('init <name>') // 定义init命令
.description('init project')
.action(name => { // 指定命令要做什么事,回调函数中实现命令功能
console.log('init ' + name);
})
program.parse(process.argv)
3、添加bin命令,修改package.json:
{
"bin": {
"kkb": "./bin/kkb.js",
},
}
4、链接命令:执行npm link,把命令链接到全局,相当于全局安装项目。
最后在命令行运行kkb,就会执行auto-cli/bin/kkb.js命令文件。简单的cli命令工具就完成了。
进阶1:在控制台打印个性化欢迎界面
(1)新建/lib/init.js文件
const {promisify} = require('util') // util 是一个Node.js 核心模块,提供常用函数的集合,用于弥补核心JavaScript 的功能 过于精简的不足
const figlet = promisify(require('figlet')) // util.promisify() 这个方法,方便快捷的把原来的异步回调方法改成返回 Promise 实例的方法
const clear = require('clear')
const chalk = require('chalk')
const log = content => console.log(chalk.green(content));
module.exports = async name => {
// 打印欢迎界面
clear()
const data = await figlet('KKB Welcom') // figlet是把文字变成大字
log(data);
}
(2)修改init命令回调函数
program
.command('init <name>') // 定义init命令
.description('init project')
.action(require('./init.js'))
program.parse(process.argv)
此时执行kkb init xx,就会在控制台输出大字界面。
进阶2:通过init命令初始化项目
初始化项目的本质就是从gitlab上下载一个项目模板到本地。
(1)新建/lib/download.js文件,实现下载模板
const {promisify} = require('util')
module.exports.clone = async function(repo, desc) {
const download = promisify(require('download-git-repo')) // download-git-repo: Download and extract a git repository (GitHub, GitLab, Bitbucket)
const ora = require('ora')
const process = ora(`下载......${repo}`)
process.start() // 进度条开始
await download(repo, desc)
// download-git-repo导出的download方法,第一个参数repo是仓库地址,格式有三种:
// GitHub - github:owner/name or simply owner/name
// GitLab - gitlab:owner/name
// Bitbucket - bitbucket:owner/name
process.succeed()
}
(2)在/lib/init.js中引入download.js,完成项目初始化
const {promisify} = require('util') // util 是一个Node.js 核心模块,提供常用函数的集合,用于弥补核心JavaScript 的功能 过于精简的不足
const figlet = promisify(require('figlet')) // util.promisify() 这个方法,方便快捷的把原来的异步回调方法改成返回 Promise 实例的方法
const clear = require('clear')
const chalk = require('chalk')
const log = content => console.log(chalk.green(content));
const {clone} = require('./download')
module.exports = async name => {
// 打印欢迎界面
clear()
const data = await figlet('KKB Welcom') // figlet是把文字变成大字
log(data);
// clone
log(`创建项目: ${name}`);
await clone('github:su37josephxia/vue-sample', name)
}
进阶3:自动安装依赖,自动启动和打开浏览器,在node中执行shell命令
(1)在/lib/init.js中创建子进程执行shell命令
const {promisify} = require('util') // util 是一个Node.js 核心模块,提供常用函数的集合,用于弥补核心JavaScript 的功能 过于精简的不足
const figlet = promisify(require('figlet')) // util.promisify() 这个方法,方便快捷的把原来的异步回调方法改成返回 Promise 实例的方法
const clear = require('clear')
const chalk = require('chalk')
const log = content => console.log(chalk.green(content));
const {clone} = require('./download')
const open = require('open')
const spawn = async (...args) => {
const {spawn} = require('child_process')
return new Promise(resolve => {
const proc = spawn(...args) // 在node.js中执行shell一般用spawn,实现从主进程的输出流连通到子进程的输出流
proc.stdout.pipe(process.stdout) // 子进程正常流搭到主进程的正常流
proc.stderr.pipe(process.stderr) // 子进程错误流插到主进程的错误流
proc.on('close', () => {
resolve()
})
})
}
module.exports = async name => {
// 打印欢迎界面
clear()
const data = await figlet('KKB Welcom') // figlet是把文字变成大字
log(data);
// clone
log(`创建项目: ${name}`);
// await clone('github:su37josephxia/vue-sample', name)
// 自动安装依赖
log('安装依赖')
console.log(spawn);
await spawn('npm',['install'],{cwd: `./${name}`})
log(`安装完成:To get Start: cd ${name} \n npm run server`)
// 自动打开浏览器
open(`http://localhost:8080`)
// 自动启动项目
await spawn('npm',['run', 'dev'],{cwd: `./${name}`})
}
进阶4:通过命令自动生成路由及菜单
(1)新建/lib/refresh.js文件
const fs = require('fs')
const hbs = require('handlebars')
const chalk = require('chalk')
module.exports = async () => {
// 获取列表
const list = fs.readdirSync('./src/views')
.filter(v => v !== 'Home.vue')
.map(v => ({
name: v.replace('.vue', '').toLowerCase(),
file: v
}))
// 生成路由文件
compile({list}, './src/router.js', './template/router.js.hbs')
// 生成菜单
compile({list}, './src/App.vue', './template/App.vue.hbs')
//meta:数据定义 filePath:目标文件 templatePath:模板文件
function compile(meta, filePath, templatePath) {
if (fs.existsSync(templatePath)) {
const content = fs.readFileSync(templatePath).toString()
const result = hbs.compile(content)(meta)
fs.writeFileSync(filePath, result)
console.log('创建成功');
}
}
}
(2)在auto-cli/bin/kkb.js命令文件中增加命令
program
.command('refresh') // 定义init命令
.description('refresh routers')
.action(require('../lib/refresh'))
项目(auto-cli/lib)最终文件代码:
(1)/bin/kkb.js
#!/usr/bin/env node
console.log('auto-router-cli....')
const program = require('commander') //命令行工具
program.version(require('../package.json').version) // 或直接写 '1.0.1'
program
.command('init <name>') // 定义init命令
.description('init project')
// .action(name => { // 指定命令要做什么事,回调函数中实现命令功能
// console.log('init ' + name);
// })
.action(require('./init.js'))
program
.command('refresh') // 定义init命令
.description('refresh routers')
.action(require('./refresh'))
program.parse(process.argv)
(2)/lib/init.js
const {promisify} = require('util') // util 是一个Node.js 核心模块,提供常用函数的集合,用于弥补核心JavaScript 的功能 过于精简的不足
const figlet = promisify(require('figlet')) // util.promisify() 这个方法,方便快捷的把原来的异步回调方法改成返回 Promise 实例的方法
const clear = require('clear')
const chalk = require('chalk')
const log = content => console.log(chalk.green(content));
const {clone} = require('./download')
const open = require('open')
const spawn = async (...args) => {
const {spawn} = require('child_process')
return new Promise(resolve => {
const proc = spawn(...args)
proc.stdout.pipe(process.stdout) // 子进程正常流搭到主进程的正常流
proc.stderr.pipe(process.stderr) // 子进程错误流插到主进程的错误流
proc.on('close', () => {
resolve()
})
})
}
module.exports = async name => {
// 打印欢迎界面
clear()
const data = await figlet('KKB Welcom') // figlet是把文字变成大字
log(data);
// clone
log(`创建项目: ${name}`);
await clone('github:su37josephxia/vue-sample', name)
// 自动安装依赖
log('安装依赖')
console.log(spawn);
await spawn('npm',['install'],{cwd: `./${name}`})
log(`安装完成:To get Start: cd ${name} \n npm run server`)
// 自动打开浏览器
open(`http://localhost:8080`)
// 自动启动项目
await spawn('npm',['run', 'dev'],{cwd: `./${name}`})
}
(3)/lib/download.js
const {promisify} = require('util')
module.exports.clone = async function(repo, desc) {
const download = promisify(require('download-git-repo')) // download-git-repo: Download and extract a git repository (GitHub, GitLab, Bitbucket)
const ora = require('ora')
const process = ora(`下载......${repo}`)
process.start() // 进度条开始
await download(repo, desc)
// download-git-repo导出的APIdownload方法,第一个参数仓库地址:repo的格式
// GitHub - github:owner/name or simply owner/name
// GitLab - gitlab:owner/name
// Bitbucket - bitbucket:owner/name
process.succeed()
}
(4)/lib/refresh.js
const fs = require('fs')
const hbs = require('handlebars')
const chalk = require('chalk')
module.exports = async () => {
// 获取列表
const list = fs.readdirSync('./src/views')
.filter(v => v !== 'Home.vue')
.map(v => ({
name: v.replace('.vue', '').toLowerCase(),
file: v
}))
// 生成路由文件
compile({list}, './src/router.js', './template/router.js.hbs')
// 生成菜单
compile({list}, './src/App.vue', './template/App.vue.hbs')
//meta:数据定义 filePath:目标文件 templatePath:模板文件
function compile(meta, filePath, templatePath) {
if (fs.existsSync(templatePath)) {
const content = fs.readFileSync(templatePath).toString()
const result = hbs.compile(content)(meta)
fs.writeFileSync(filePath, result)
console.log('创建成功');
}
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。