一、搭建一个简单的脚手架
-
环境准备:
-
安装node环境
-
初始化项目
npm init -y -
安装 commander:
npm install commander
-
-
index.js
#!/usr/bin/env node const { program } = require('commander'); program.version(require('./package.json').version) program.parse(process.argv) // 默认参数是 process.argv,所以参数可以不传
package.json
{ "name": "my_cli", "version": "1.1.2", "description": "", "main": "index.js", "bin": { "my-cli": "index.js" }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "commander": "^9.2.0" } } -
执行
npm link- 将项目自定义的
bin命令添加到全局变量中
- 将项目自定义的
至此就可以在终端中使用自定义的 bin 命令了,这里是 my-cli
my-cli --help:查看帮助my-cli --version查看版本
二、搭建一个功能完善的脚手架
2.1、前置知识
2.1.1、commander 命令
先来熟悉要用到的api
#!/usr/bin/env node
// index.js
const { program } = require('commander');
program
// 定义cli命令
.command('create')
// 定义create命令的参数
.argument('<project-name>')
// 添加命令的描述
.description('clone a repository into a newly created directory')
// create命令执行的逻辑
.action((projectName) => {
console.log('project-name: ', projectName)
})
program.parse()
更多关于
commander的用法请参考官方文档
命令行输入: my-cli --help 结果如下:
命令行输入: my-cli create vue-app 结果如下:
2.1.2、download-git-repo 下载模版
- 安装依赖
npm install download-git-repo
因为 download-git-repo 不支持promise,所以这里使用 promisify 对 download-git-repo 进行了promise封装,具体 promisify 更多使用细节可以参考官方文档
#!/usr/bin/env node
// index.js
const { program } = require('commander');
const { promisify } = require('util')
const download = promisify(require('download-git-repo'))
program
// 定义cli命令
.command('create')
// 定义create命令的参数
.argument('<project-name>')
// 添加命令的描述
.description('clone a repository into a newly created directory')
// create命令执行的逻辑
.action(async (projectName) => {
// 1. 下载模版
console.log('init project')
// 远程模版地址,默认master分支,这里下载的是main分支
const repoUrl = 'direct:https://github.com/Micah-Yu/vue-template.git#main'
await download(repoUrl, projectName, { clone: true })
})
program.parse()
命令行执行 my-cli create vue-app
可以看到多可一个文件夹,内容就是我们远程仓库的模版
更多关于
download-git-repo的用法参考官方文档
Error: 'git clone' failed with status 128git 报错这个是文件夹存在了
2.1.3、项目依赖的安装及运行
项目的依赖的安装及运行需要用用node中的 child_process 中的 spawn开一个子进程,用于执行终端命令
封装如下:
// terminal.js
/*
* 执行终端命令相关的代码
* */
const { spawn } = require('child_process')
const spawnCommand = (...args) => {
return new Promise((resolve, reject) => {
const childProcess = spawn(...args)
// 将子进程所有的标准输出都传给父进程,显示在控制台上
childProcess.stdout.pipe(process.stdout)
// 将子进程所有的错误都传给父进程,显示在控制台上
childProcess.stderr.pipe(process.stderr)
childProcess.on('close', () => {
resolve()
})
})
}
module.exports = {
spawnCommand
}
更多关于
spawn的使用细节参考官方文档
#!/usr/bin/env node
// index.js
const { program } = require('commander');
const { promisify } = require('util')
const {spawnCommand} = require("./lib/utils/terminal.js");
const download = promisify(require('download-git-repo'))
program
// 定义cli命令
.command('create')
// 定义create命令的参数
.argument('<project-name>')
// 添加命令的描述
.description('clone a repository into a newly created directory')
// create命令执行的逻辑
.action(async (projectName) => {
// 1. 下载模版
console.log('init project')
// 远程模版地址,默认master分支,这里下载的是main分支
const repoUrl = 'direct:https://github.com/Micah-Yu/vue-template.git#main'
await download(repoUrl, projectName, { clone: true })
// 2. 安装依赖
console.log('installing dependents...')
// 这里做一个npm命令不同系统的兼容
const command = process.platform === 'win32' ? 'npm.cmd' : 'npm'
await spawnCommand(command, ['install'], { cwd: `./${projectName}` })
// 3. 启动项目
console.log('start project')
await spawnCommand(command, ['run', 'serve'], { cwd: `./${projectName}` })
})
program.parse()
终端执行 my-cli create vue-app
至此完成一个简单的自定义脚手架
其他类似 vue-cli 提示选择的功能,使用的是 inquirer 这个库实现的,官方文档