我们在前端开发中会经常用到命令行工具,比如@babel/cli、vue-cli、create-react-app 等等。那么如何创建一个npm 命令行工具呢?其实很简单的,仅需要几步即可。
创建
1 初始化npm项目
npm init
package name: (cli) gogocode-cli
version: (1.0.0)
description: my-first-cli
entry point: (index.js)
keywords: npm cli
author: super man
2 配置bin字段
npm init 后会生成一个package.json文件,在该文件中添加一个bin字段,bin字段的key就是你的命令(gogocode),value指向相对于package.json的路径(index.js),不同的key对应不同的命令。关于 bin 字段更多信息请参考文档。
{
"name": "gogocode-cli",
"version": "1.0.0",
"description": "my-first-cli",
"bin": {
"gogocode": "index.js"
}
}
3 创建index.js文件
在项目根目录创建index.js文件。下面是index.js文件内容:使用console.log() 函数来输出命令行返回信息。
#!/usr/bin/env node
console.log('Hello, world!');
注意:第一行一定要添加脚本来指定运行环境(#!/usr/bin/env node)
4 打包发布
4.1 发布
- 在项目根目录执行npm pulish 命令。按照系统提示操作,即可将你的命令行工具发布到 npmjs 平台。期间需要注册npm账号,可自行百度。
npm publish
- 打包完成之后,就能在npmjs官网看到你发布的npm包了。
4.2 验证
- 全局安装 npm 包
npm install gogocode-cli -g
- 执行命令
gogocode
- 正确输出 “Hello,World!” 😊
进阶&工具
上面只是把npm命令行工具从准备到发布简单跑通,如果需要构建复杂的npm命令行应用还需要借助一些辅助开发包。下面介绍两个比较常用npm包: commander 和 terminal-kit
Commander
-
commander用于组织命令行指令(command)和参数(option),它主要负责对命令行的输入信息进行处理。
- command 可以理解为“指令”用于定义一个代码逻辑。一般指的是命令行工具第一个空格和第二个空格之间的文本。比如: npm init,其中init就是一个command。一个命令行工具可以支持多个指令输入。
- option 可以理解为“指令”的函数入参。以 “-” 或者 “--” 开头,比如:ls -a,其中-a就是一个参数,代表列出全部文件。注意:“-” 为 “--”的简写形式。
-
下面以我们最近开发的一个命令行工具 gogocode-cli 为例,为大家具体讲解下 commander 如何使用。
- 首先我们看下入口文件index.js的代码:
#!/usr/bin/env node
const program = require('commander');
const term = require('terminal-kit').terminal;
const pkg = require('./package.json');
//插件加载及执行逻辑
const transform = require('./transform');
//初始化插件项目逻辑
const init = require('./commands/init');
// 配置command
program
.command(`init`)
.description('初始化一个插件sample项目')
.action((options) => {
init(options);
});
// 配置options
program.option('-t, --transform <package name or path>', '插件路径或者npm包名称,支持多个插件,逗号分隔')
.option('-o, --out <path>', '输出文件路径')
.option('-s, --src <path>', '需要转换的源文件路径')
.action((options) => {
return transform(options);
});
// 配置 cli 信息,版本、cli说明等
program
.version(pkg.version)
.description(term.blue('GoGoCode 代码转换从未如此简单 https://gogocode.io'));
console.log();
// 接管命令行输入,参数处理
program.parse(process.argv);
- 上面的代码我们可以看出:gogocode-cli 对外支持 init 指令(command) 和 -t,-o,-s 等参数(option)定义,具体定义如下:
参数|指令 | 缩写 | 参数说明 | 类型 |
---|---|---|---|
init | init | 初始化一个插件sample项目 | command |
--src | -s | 需要转换的源文件路径 | option |
--transform=FILE/npm package | -t | 插件路径或者npm包名称 | option |
--out | -o | 输出文件路径 | option |
- 我们执行一下 index.js:
node ./index.js
结果如下:
我们可以看到 commander 自动帮我们处理指令和参数显示及逻辑拆分问题,同时自动添加 -V,-h 两个option。可以说非常方便。
terminal-kit
terminal-kit 是一个功能强大的命令行输出工具,支持文本样式、table、menu、进度条等多种交互形式。下面简单介绍一下几个常用功能。
- 字体颜色,输出蓝色文本
const term = require('terminal-kit').terminal;
term.blue('GoGoCode 代码转换从未如此简单 https://gogocode.io');
- table表格输出
const term = require('terminal-kit').terminal;
term.table([
['header #1', 'header #2', 'header #3'],
['row #1', 'a much bigger cell, a much bigger cell, a much bigger cell... ', 'cell']
], {
hasBorder: false,
contentHasMarkup: true,
textAttr: { bgColor: 'default' },
firstCellTextAttr: { bgColor: 'blue' },
firstRowTextAttr: { bgColor: 'yellow' },
firstColumnTextAttr: { bgColor: 'red' },
checkerEvenCellTextAttr: { bgColor: 'gray' },
width: 60,
fit: true // Activate all expand/shrink + wordWrap
}
);
- Yes or No 询问
const term = require('terminal-kit').terminal;
term('Do you like gogocode? [Y|n]\n');
term.yesOrNo({ yes: ['y', 'ENTER'], no: ['n'] }, function (error, result) {
if (result) {
term.green("'Yes' detected! Good bye!\n");
process.exit();
}
else {
term.red("'No' detected, are you sure?\n");
}
});
调试
命令行工具开发过程中该如何进行Debug呢?我们可以这样操作。
- 将vscode(最新版本)内置终端(terminal)切换到 JavaScript Debug Terminal
- 使用vscode内置断点功能,打断点。
- JavaScript Debug Terminal 中执行 node ./index.js 即可debug
gogocode
以上npm命令行开发经验都是小编在开发 gogocode-cli 过程中总结而来。gogocode-cli 是 gogocode 的命令行工具。那 gogocode 是什么东东呢?引用一下官方介绍:
GoGoCode是一个操作AST的工具,可以降低使用AST的门槛,帮助开发者从繁琐的AST操作中解放出来,更专注于代码分析转换逻辑的开发。简单的替换甚至不用学习AST,而初步学习了AST节点结构(可参考AST查看器)后就可以完成更复杂的分析转换。
gogocode的官方文档 gogocode.io/zh/docs/spe…
gogocode可以说是一个上手快、使用爽的代码转换工具。
gogocode转换插件
既然gogocode这么好用,那么我们如何使用gogocode来编写转换插件呢?下面为大家讲解下吧:
插件初始化
- 首先需要安装gogocode-cli
npm install gogocode-cli -g
- 之后执行 “gogocode init” 来初始化一个插件项目
gogocode init
插件项目结构
gogocode init 初始化后的插件目录,是一个标准的npm项目。项目的主入口配置在package.json的main节点。
上图截图我们可以看到,插件项目转换逻辑入口为transform.js,具体定义如下:
/**
* 转换入口导出一个函数,按照如下函数签名
* @param {*} fileInfo 包含 source 和 path 属性。source为待转换文本,path为路径
* @param {*} api 包含 gogocode 作为转换工具
* @param {*} options 其他 option 由此传入
* @returns {string} 返回转换后的代码
*/
module.exports = function(fileInfo, api, options) {
const sourceCode = fileInfo.source;
const $ = api.gogocode;
return $(sourceCode)
.replace('const a = $_$', 'const a = 2')
.generate();
};
我们的转换逻辑需要定义在上面的函数中
转换逻辑执行
gogocode-cli 执行 js文件
转换逻辑可以以js文件的形式执行,下面是具体命令:
gogocode -s ./test/input.vue -t ./transform.js -o out.vue
其中,gogocode-cli 命令行参数定义可以参考上面 commander 章节中gogocode-cli的参数定义。
gogocode-cli 执行 npm包
如果想把自己写好的插件分享给大家,可以直接把这个项目打包成npm包。
gogocode-cli同时也支持运行npm转换逻辑的功能。
例如我们发布了一个“vue2-to-3”的npm插件。可以执行下面命令,来运行npm包里面的转换逻辑。
gogocode -s ./test/input.vue -t ./vue2-to-3 -o out.vue
GoGoCode 相关链接
GoGoCode的Github仓库(新项目求star _)
https://github.com/thx/gogocode
GoGoCode的官网
https://gogocode.io/
可以来 playground 快速体验一下
https://play.gogocode.io/
阿里妈妈出的新工具,给批量修改项目代码减轻了痛苦
「GoGoCode 实战」一口气学会 30 个 AST 代码替换小诀窍
0成本上手AST,用GoGoCode解决Vue2迁移Vue3难题
GoGoCode协助清理代码中的「垃圾」