在我们使用 vue 开发项目的时候,一般都是使用命令行直接生成项目模板,eg:
$ yarn create vite-app <project-name>
$ cd <project-name>
$ yarn
$ yarn dev
复制代码
$ yarn create vite-app <project-name>
// 等同于
$ yarn global add create-vite-app
$ create-vite-app <project-name>
复制代码
如果我们想自己弄一个 cli 工具来管理自己的项目模板,该怎么弄呢?在这里写一个简单 cli 工具通过命令行来拉取已定义的模板。
初建项目
创建一个目录,然后初始化:
mkdir test-cli // 创建目录
cd test-cli // 进入目录
npm init -y // 初始化npm
复制代码
然后安装一些需要用到的 npm 包:
npm install commander download-git-repo ora handlebars figlet clear chalk -s
复制代码
注册全局命令
我们需要在系统环境上注册一个全局命令。
新增 bin/index.js 文件:
mkdir bin
// bin/index.js
#!/usr/bin/env node // 指定文件解释器
// 告诉操作系统,当执行这个文件的时候,调用系统环境下的node解释器
console.log('test 111 ...')
复制代码
在 package.json 新增 bin 命令:
{
"bin": {
"tcli": "./bin/index.js"
}
// ......
}
复制代码
然后执行 npm link,等执行完成之后,在命令行输入 tcli 就能执行 ./bin/index.js 文件了。
npm link 是将本地包进行临时的全局安装,相当于 npm install -g xxx,会引起全局污染,有可能会全局安装失败,需要管理员权限。
创建node命令
#!/usr/bin/env node
// 引入自定义命令组件
const program = require('commander')
// 设置版本号
program.version(require('../package').version)
// 设置 init 命令,name 为参数
program.command('init <name>')
.description('init project') // 设置init命令的描述
.option('-s, --session', 'session param') // 设置参数
.action((name, params) => { // 执行逻辑
console.log('params => ', name)
console.log('params.session => ', params.session)
})
// 命令的执行其实是 commander 解析 process.argv 参数来启动
program.parse(process.argv);
复制代码
下载模板
修改 program.action 方法:
program.command('init <name>')
.description('init project')
.option('-s, --session', 'session param')
.action(require('../lib/init'))
复制代码
新建 lib/init.js
// lib/init.js
const { promisify } = require('util') // 将函数转为promise格式
const figlet = promisify(require('figlet')) // 字体包
const clear = require('clear') // 控制台清屏
const chalk = require('chalk') // 修改控制台中字符串的样式
const log = ctx => console.log(chalk.green(ctx)) // 封装日志输出
module.exports = async name => {
clear()
const data = await figlet('Hello ' + name)
log(data)
}
复制代码
新建一个 lib/download.js 文件,处理模板下载逻辑:
// lib.download.js
const { promisify } = require('util')
/**
* repo 下载的模板路径
* desc 下载的目标路径地址
*/
module.exports.clone = async function(repo, desc) {
const download = promisify(require('download-git-repo')) // 下载组件
const ora = require('ora')
const process = ora(`⏳下载...... ${repo}`) // 用于显示加载效果,类似页面的 loading 效果
process.start()
await download(repo, desc)
process.succeed()
}
复制代码
修改 lib/init.js,封装 spawn 命令,在 init 初始化加入下载模板,安装依赖
// 新增 clone 引入
const { clone } = require('./download')
// 封装 spawn 命令
// 子进程输出流引入主进程输出流
const spawn = async (...args) => {
const { spawn } = require('child_process')
const options = args[args.length - 1]
// 如果系统为windows,则需要修改 shell 为 true
if (process.platform === 'win32') {
// 设置 shell 为 true,以隐式的调用 cmd
options.shell = true
}
return new Promise(resolve => {
const proc = spawn(...args)
// proc(子) -> process(主)
proc.stdout.pipe(process.stdout) // 标准输出
proc.stderr.pipe(process.stderr) // 标准错误输出
proc.on('close', resolve)
})
}
module.exports = async name => {
// 打印欢迎页面
clear()
const data = await figlet('Hello ' + name)
log(data)
log('?创建项目 ' + name)
await clone('github:554246839/project-template', name)
// 安装依赖
log('?安装依赖......')
await spawn('yarn', ['install'], { cwd: `./${name}` })
log(`
?安装完成
To get start
======================
cd ${name}
yarn dev
======================
`)
}
复制代码
功能到这已经差不多完成了,看下效果。
在其它地方新建一个目录,然后执行下载安装:
如果想根据参数下载不同的项目模板,可以直接修改 lib/init.js 的 exports 方法:
新建 template.js 模板管理文件:
// lib/template.js
module.exports.templates = {
project1: 'github:554246839/project-template',
project2: 'github:554246839/project-template',
project3: 'github:554246839/project-template'
}
// lib/init.js
// 新增
const { templates } = require('./template')
function getParam(params) {
let p = Object.keys(params)
for (let i = 0; i < p.length; i++) {
if (params[p[i]]) {
return p[i]
}
}
}
// 修改
module.exports = async (name, params) => {
// 打印欢迎页面
clear()
const data = await figlet('Hello ' + name)
log(data)
log('?创建项目 ' + name)
await clone(templates[getParam(params) || 'project1'], name) // 修改
// 安装依赖
log('?安装依赖......')
await spawn('yarn', ['install'], {cwd: `./${name}`})
log(`
?安装完成
To get start
======================
cd ${name}
yarn dev
======================
`)
}
复制代码
GitHub:github.com/554246839/t… master 分支
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END