前端开发过程中经常会遇到各种 cli,比如 dva-cli
、vue-cli
和 ant-design-pro-cli
等,这些都是基于 node 开发的命令行工具,本文以开发一个生成脚手架的命令行工具为例学习一下具体的开发流程.实现的需求就是通过 npm 全局安装这个 node 包,根据提示在命令行进行选择、输入等操作,最终生成一个以 react
或 vue
为基础的脚手架.当然,前提是必须要有现成的 react
或 vue
脚手架模版(这个不是本文的重点).
初始化项目
- 创建目录并命名为
gframe
(generate frame 的缩写) npm init -y
生成package.json
,修改 name,version,description 的值- 新建 bin 目录和 gframe 文件
- 安装依赖包
项目目录简介
新建 bin 目录,并在 bin 目录下创建gframe
文件,由于只是一个简单的小项目,所有的代码都写在 gframe 里边了.该文件的头部要加上#!/usr/bin/env node
,表示使用 node 作为脚本的解释执行.
解析处理命令行 commander
- version 方法输出版本信息
- command 注册命令,参数是命令名称和回传给 action 方法的参数
- description 输出该命令的描述
- action 订阅了该命令触发时的回调函数
- parse 对传入的参数进行解析并执行相应的回调
const program = require('commander');
program
.version(pkg.version, '-v,--version')
.command('init <dirname>')
.description(pkg.description)
.action(dirname => {
// 命令init触发时的回掉
});
program.parse(process.argv);
复制代码
命令行交互 inquirer
- 通过 prompt 方法配置交互方式
- 通过.then 中的参数获取交互结果
var inquirer = require('inquirer');
inquirer
.prompt([
{
type: 'list', // 还有input,checkbox,password等类型
name: 'frame',
message: '请选择开发用的脚手架:',
choices: ['react', 'vue']
},
...
])
.then(answers => {
// 通过answers拿到用户交互的结果,然后可以处理其他逻辑
const {frame} = answers;
...
});
复制代码
下载模版 download-git-repo
- 支持从 github|gitlab|bitbucket 上下载代码
- 通过 bluebird 的 promisify 包装,用.then 替换 callback
- download 的两个必须参数,repo 指仓库地址,dest 指下载的目标路径
- 需要注意的是仓库地址 com 或者端口号后面的'/'要改为':',最后面还需要用#拼上'分支名',eg:
https://mygitlab.com:flipxfx/download-git-repo-fixture#my-branch
const Promise = require('bluebird');
const download = Promise.promisify(require('download-git-repo'));
download(repo, dest).then(() => {
// 下载成功后,根据命令行交互的内容,重写下载到本地的package.json
const pkg = process.cwd() + `/${dest}/package.json`;
const content = JSON.parse(fs.readFileSync(pkg, 'utf8'));
content.name = name; // 用户输入的项目名称
content.description = description; // 用户输入的项目简介
const result = JSON.stringify(content);
fs.writeFileSync(pkg, result);
});
复制代码
小图标美化 ora
要手动调用spinner.stop
方法结束,否则程序不会退出,因为内部是通过 setInterval
定时器实现的
const ora = require('ora');
const spinner = ora('正在下载模板...');
spinner.start();
setTimeout(() => {
spinner.stop();
}, 1000);
复制代码
本地测试
- package.json 中增加 bin 字段,它是一个命令名和本地文件名的映射
- 在项目根目录下执行 npm link,这样会在全局的 node_modules 下生成一个符号链接,此时就可以在全局使用 package.json 中 bin 字段的命令名了
npm 发布
- 在
https://www.npmjs.com
上注册账号,已有 npm 账号的直接登录 - 项目根目录下执行
npm adduser
,输入用户名、密码、邮箱后,如果登录成功会提示:Logged in as 'username' on https://registry.npmjs.org/
. - 项目根目录下执行
npm publish
- 发布过程中如果提示
You do not have permission to publish "packagename". Are you logged in as the correct user?
先检查本地登录的用户是否和www.npmjs.com上的用户是否一致,如果没问题,则把package.json
中的name
的值改掉,因为包名已经被别人使用了,所以不能正常发布
使用
按照下图的演示操作后,当前执行命令的目录下就会新增一个my-app
的项目,里边有现成的脚手架,然后就可以愉快地开发了