需要用到的几个Node.js包(每个模块使用方法自行github搜索):
-
commander
负责将输入到终端的参数解析为选项和命令参数;生成基础的命令选项
-
inquirer
命令行问答模块,自定义问题并对根据用户回答做处理
-
chalk
修改终端输出文字的样式
-
ora
在终端显示loading加载动画
-
download-git-repo
从 GitHub、GitLab、Bitbucket 等平台下载仓库
-
fs
Node.js的内置读写文件目录的模块
基本流程:
生成 package.json 文件,并添加 bin 属性;
在 bin 属性值指定的目录位置处编写命令脚本;
运行 npm link 将编写的命令行工具添加到 Node.js 全局模块目录;
终端中运行命令行工具测试;
发布到 npmjs.com;
全局安装测试。
流程记录:
1. 在 /test 测试目录下运行 npm init -y 生成package.json文件;
- 安装依赖
npm install commander inquirer@^8.0.0 chalk@^4.0.0 ora@^5.0.0 download-git-repo
3. package.json中添加 bin 属性
{
"name": "pro-cli",
"version": "1.0.0",
"bin": {
"pro-cli": "bin/pro-cli.js"
},
- 根据bin属性,创建工具目录:
上面示例 pro-cli: 'bin/pro-cli.js
表示在终端中运行 pro-cli 命令时,执行当前路径下bin目录中的 pro-cli.js 文件;所以创建 bin 目录,在其下添加pro-cli.js文件,并在该js文件中编写脚本
- 在 /bin/pro-cli.js 中编写脚本:
#! /usr/bin/env node
const commander = require('commander')
commander
.version(require('../package.json').version)
.usage('<command> [options]')
.command('init', '创建一个vue或react基础项目')
commander.parse(process.argv)
#! /usr/bin/env node 为固定写法;
commander使用方法参考:github.com/tj/commande…
.version 定义工具版本,从package.json文件中读取version字段值
.usage 说明该命令行工具使用方式
.command 定义子命令,这里定义了一个 init 子命令,通过 pro-cli init 执行;
读过commander使用方法后知道,这里没有使用.action 定义运行子命令要执行的动作,所以commander会在bin目录下搜索
pro-cli-init.js
这个文件名是根据 总命令-子命令 这样的规则生成,commander会自动寻找该文件。
- pro-cli.js 同级目录添加 pro-cli-init.js 文件。把pro-cli.js作为命令行工具入口文件,pro-cli-init.js作为运行init子命令时执行文件。如果在该文件中添加
console.log('pro-cli init命令');
这样的内容,然后运行 npm link 链接到node.js全局模块目录后,在终端中运行 pro-cli init 命令,就会执行 pro-cli-init.js 文件,打印出该语句。
pro-cli-init.js文件内容:
#! /usr/bin/env node
const inquirer = require('inquirer');
const downloadGIt = require('download-git-repo');
const ora = require('ora')
const chalk = require('chalk')
const fs = require('fs')
// const rimraf = require('rimraf');
const { projectName, frameworkList, vueVersions, gitRepos } = require('./config');
const { dirIsExist } = require('./utils')
inquirer.prompt(projectName).then(async projName => {
dirIsExist(process.cwd() + '/' + projName.projectName, projName.projectName)
let ans = await inquirer.prompt(frameworkList)
let selectFrameworkType = ans.frameworkType.toLowerCase()
if (selectFrameworkType == 'vue') {
let selectVueVersion = await inquirer.prompt(vueVersions)
selectVueVersion = selectVueVersion.vueVersion
let confirmGitUrl = gitRepos.find(item => item.type == selectFrameworkType && item.version == selectVueVersion.slice(0, selectVueVersion.indexOf('.')))
fetchGit(confirmGitUrl.url, projName.projectName)
} else {
let confirmGitUrl = gitRepos.find(item => item.type == selectFrameworkType)
fetchGit(confirmGitUrl.url, projName.projectName)
}
})
function fetchGit(gitUrl, projectName) {
// 等待动画
const spinner = ora('fetching template...').start()
downloadGIt(gitUrl, process.cwd() + '/' + projectName, err => {
if (err) {
console.log();
console.log(chalk.red(err));
spinner.fail('基础模板下载失败')
process.exit(1)
}
spinner.succeed(chalk.green('项目创建成功'))
console.log();
console.log(chalk.green(`
================================================
cd ${projectName}
安装依赖:npm install / yarn install
运行:npm start / yarn start
================================================
`));
})
}
从当面目录下的config.js和utils.js文件中引入了方法,config.js和utils.js文件具体为:
pro-cli-init.js 文件解释:
从 config.js 中引入了 项目名、框架类型、vue版本和预设的git配置4个问题;
从 utils.js 中引入了判断目录是否存在的方法
询问项目名(作为目录名),判断是否存在;
询问项目使用的框架(vue或者react);
如果选择了vue,询问使用2.x还是3.x版本;
根据选择的框架获取预设的框架模板所在地址;
拿到git地址后通过 download-git-repo 模块进行下载,下载过程通过 ora 模块展示loading动画,如果下载模块出错就终止运行;下载成功显示提示信息。
发布到 npmjs
发布到 npmjs.com, 需要到该网站进行用户注册,然后在编写的命令行所在目录下运行 npm publish, 会提示需要先登陆,运行 npm adduser 输入注册时的用户名和密码登陆后 npm publish 发布;可能提示没有权限,大概率是因为npmjs.com 已经有同名的包了,修改一下package.json中neme值重新publish即可。发布成功后可以全局安装该包进行测试。 上面示例全局安装就是 npm i -g pro-cli,然后运行 pro-cli 会显示帮助信息。
需要注意的是,如果npm使用了taobao镜像,需要切换回原npm镜像,然后再发布。为方便切换,可安装nrm。