cli 功能说明
- 初始化项目,自动下载github模板资源,并且自动安装
- 依赖安装后自动启动模板仓库
- 实现约定式路由
依赖安装
$ yarn add commander download-git-repo ora handlebars figlet clear chalk open watch -D
-
依赖说明:
- commander Nodejs 命令配置工具
- inquirer 一组常用的交互式命令行用户界面。
- download-git-repo 下载 github 资料的工具
- ora 一个优雅的终端加载器
- handlebars 一个简单的模板语言
- figlet 在终端中打印好看的自定义提示语的工具
- clear 终端清屏工具,功能等同 linux 命令
clear,windows 的cls - chalk 类似终端的画笔工具,可以给 log 不同颜色样式的提示语
- open 用于自动打开浏览器
- watch 用于监听文件变化
初始化
-
新建文件夹:
ddb -
进入该文件夹,使用
npm初始化:npm init -y -
新建相关文件:
- 新建
/bin/ddb.js - 新建
/lib/init.js - 新建
/lib/download.js - 新建
lib/refresh.js
- 新建
-
配置
package.json
{
"name": "my-cli",
"version": "1.0.0",
"description": "",
"main": "kkb.js",
"bin": {
"my-cli": "./bin/kkb.js"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
复制代码
- 绑定软连接:
npm link
开始实现
获得版本号
- 在
/bin/kkb.js中编写代码如下
#!/usr/bin/env node
'use strict';
const program = require('commander')
// 策略模式
program.version(require('../package').version)
program.parse(process.argv)
复制代码
- 在终端输入命令:
my-cli -V,是否显示对应的版本号,如果有,则说明前面我们的配置都是成功的
打印初始化提示语
- 编写
/lib/init.js文件如下:
const figlet = promisify(require('figlet'))
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('my-cli welcome', {
font: 'Ghost',
horizontalLayout: 'default',
verticalLayout: 'default',
width: 80,
whitespaceBreak: true
})
log(data)
}
- 修改
/bin/ddb.js代码
#!/usr/bin/env node
'use strict';
const program = require('commander')
// 策略模式
program.version(require('../package').version)
program.command('init <name>')
.description('init project')
.action(
require('../lib/init')
)
program.parse(process.argv)
复制代码
-
测试 ,在终端输入命令
my-cli init demo,我们可以看到终端输出的很大的my-cli welcome字样 -
接下来,我们继续编写
init方法,它主要包括以下几个功能- download 下载 选中的 模板信息
- install 为该模板安装依赖
- open 安装依赖后自动打开浏览器预览
-
下载 选中的模板信息,编写
/lib/download.js文件
const { promisify } = require("util")
const ora = require('ora')
module.exports.clone = async function(repo,desc) {
const download = promisify(require("download-git-repo"))
const process = ora(`正在下载...${repo}`)
process.start();
await download(repo, desc);
process.succeed();
}
注:如果ora报错,降低ora版本到5
- 修改/lib/init.js 文件
const {clone} = require('./download')
module.exports = async name => {
//...
//下载项目模版
log('🚀创建项目'+ name)
await clone('github:su37josephxia/vue-template',name)
//...
}
- 然后进行依赖的安装,还是在/lib/init.js 文件中进行修改
require('child_process')
const ora = require('ora')
const spawn =async(...args) => {
// 同步 Promise api
// 输出流 子进程流合并到主进程
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 => {
//...
//下载依赖 npm i
//子进程
const installProc = ora(`🏃安装依赖...`)
installProc.start();
await spawn('npm',['install'],{cwd:`./${name}`})
installProc.succeed();
log(chalk.green(`
👌安装完成
To get Start:
===================
cd ${name}
npm run serve
===================
`))
}
- 接下来,我们实现 自动打开浏览器和 启动项目,编辑
/lib/init.js
const open = require('open')
//...
module.exports = async name => {
//...
open('http://localhost:8080')
await spawn('npm',['run','serve'],{cwd:`./${name}`})
}
至此,我们就已经实现了上面的需求啦,接下来,我们来实现路由约定式路由配置
约定式路由配置
在 vue 开发过程中,我们有一个操作是必定会重复的,我们可以使用 命令的方式来实现:
- 新增一个页面
- 配置路由信息
- 其他页面添加这个新页面
//读文件列表
//拼代码 模版渲染读方式
const fs = require('fs')
const handlebars = 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')
/**
* 模板编译
* @param {*} meta 数据定义
* @param {*} filePath 目标文件
* @param {*} templatePath 模板文件
*/
function compile(meta,filePath,templatePath){
if(fs.existsSync(templatePath)){
const content = fs.readFileSync(templatePath).toString();
const result = handlebars.compile(content)(meta);
fs.writeFileSync(filePath,result);
console.log(chalk.green(`🚀${filePath}创建成功`))
}
}
}
- 在
/lib/init.js加入
program
.command("refresh")
.description("refresh routers and menu")
.action(require('../lib/refresh'))
复制代码
-
测试:
- 在
模板文件/src/views/目录下新建Test.vue,内容为
<template> <div class="test"> <h1>This is an Test page</h1> </div> </template> 复制代码- 执行
ddb refresh后,即可看到成功提示,查看模板文件/src/routers.js和模板文件/src/App.vue,即可看到新增的Test相关路由和 tab - 界面
localhost:8080也可以看到对应的效果
- 在
到这里,手写 cli 就完成啦
参考资料:
- 手写一个cli juejin.cn/post/692050…