Awesome Command-line Utilities
2018-07-09 · 2,831 chars · 15 min read
近年来,在 Node.js 的推动下,前端技术大放异彩,告别“石器时代”,进入“工业时代”。随着前端项目复杂度的不断加深,工程化、规范化、自动化等主题,摆在了所有前端开发者的面前,而这些主题无不例外都是构建在以 Node.js 为基础的工具上的。
在最近的实践过程中,发现了不少好用的库。在这里集中整理,推荐给大家,帮大家省去一些搜索和试用的时间。
下面推荐的库大部分都是我使用过的,可能还有同类型更好的选择,欢迎大家补充。
1. UI#
1.1. blessed#
项目地址: https://github.com/chjj/blessed
blessed 是一个命令行布局 & 交互工具,可以想象成命令行里的 Html 和 CSS。著名的进程管理工具 PM2 的 monitor 就是基于 blessed 开发的。
它主要提供了 Box,List,Form,Prompts,Data Display,Image 等部件,以及 Tags,Style 等样式工具。用起来还是有点小复杂的,需要用的话,读读它的文档吧。
1.2. blessed-contrib#
项目地址:https://github.com/yaronn/blessed-contrib
blessed 是个比较底层的库,直接使用比较麻烦。blessed-contrib 是基于 blessed 开发的 terminal dashboards 库,它实现了很多开箱即用的模块,如线形图,柱形图等。
这是 blessed-contrib 项目中的一个示例,是不是很炫酷?
1.3. cli-table#
项目地址:https://github.com/Automattic/cli-table
很多时候我们不需要使用 blessed 这样的大杀器,如果只是想画个简单的表格,可以使用 cli-table,pm2 的 list 命令输出的表格,就是基于 cli-table 实现的:
cli-table 还有两个兄弟项目:
它们用法类似,但都在前者的基础上增加了新功能:
- cli-table:老项目了,最近一次调整已是 4 年前了
- cli-table2:也挺老的,但还时有更新
- cli-table3:最近比较活跃(甚至还有它的维护者跑来提 PR,要我从 2 换到 3)
具体功能上的差异,可以直接看它们的文档,根据自己的需要选择。
pm2 使用的是 cli-table-redemption,基于 cli-table 做了些修改,感兴趣的话可以看看。
1.4. boxen#
项目地址:https://github.com/sindresorhus/boxen
说完 table 说 box,boxen 就是画 box 用的。可以画单线的,双线的,圆角的。简单易用,不多说,看效果:
1.5. Inquirer.js#
项目地址: https://github.com/SBoudrias/Inquirer.js
Inquirer.js 是一款非常强大的命令行 UI 工具集,包含了很多常用的工具,例如 Checkbox:
再比如,列表选择:
或者问答式的交互:
Inquirer.js 还有更多功能,直接看 Github 即可,有详细的文档和示例。类似于 vue-cli,yeoman 等脚手架工具,Inquirer.js 会非常有用。
1.6. ora#
项目地址:https://github.com/sindresorhus/ora
ora 是个 loading 工具,可以输出漂亮的 loading 效果。用法也比较简单,直接看效果:
1.7. listr#
项目地址:https://github.com/SamVerschueren/listr
有些时候你的程序可能需要一步一步的执行多个固定步骤,例如一个前端项目脚手架,可能需要先创建项目,然后根据用户选择的模板下载相应代码,最后安装依赖。对于这种类似 task list 的效果,也有相关库帮助你完成,它就是 listr:
1.8. node-progress#
项目地址:https://github.com/visionmedia/node-progress
loading 虽好,但是看不到具体进度,如果能有个进度条就更好了。node-progress 可以轻松实现多种类型的进度条展示,它的项目里有很多示例:
2. 样式效果#
2.1. chalk#
项目地址:https://github.com/chalk/chalk
chalk 是一款命令行字符样式工具,可以设置输出字符的颜色,背景,下划线等:
用法很简单自然,一看就懂:
const chalk = require('chalk') console.log(chalk.blue('Hello') + ' World' + chalk.red('!')) console.log(chalk.red('Hello', chalk.underline.bgBlue('world') + '!'))
2.2. chalk-animation#
项目地址:chalk-animation
chalk-animation 就像它的名字一样,可以实现一些动画效果,如闪烁,脉冲等:
2.3. ansi-align#
项目地址:https://github.com/nexdrew/ansi-align
ansi-align 可以将字符串居左,居中,居右对齐:
2.4. unicons#
项目地址:https://github.com/peerigon/unicons
chalk 和 ansi-align 可以设置文字的颜色和对齐方式,但是如果能输出 icon,程序会更具表现力。unicons 就可以输出一些简单的 icon:
var unicons = require('unicons') console.log(unicons.check) // ✓ console.log(unicons.cross) // ✖
2.5. figures#
项目地址:https://github.com/sindresorhus/figures
如果 unicons 不够用,那就试试 figures,它内置了更多的 icon,直接查看它的源代码找到需要的字符即可。
3. 工具#
3.1. cli-width#
项目地址:https://github.com/knownasilya/cli-width
有的时候你可能需要取当前 terminal 的宽度,cli-width 就是做这件事情的:
const cliWidth = require('cli-width') cliWidth() // maybe 204 :)
什么时候需要取宽度呢?在我的实践中,遇到过这样的需求:输出一个列表,列表前面有着重号(icon)。这在 html 里是个非常简单的需求,直接使用 ul
等列表元素即可。但是在 terminal 里,一旦某一行过长,换行之后是不会自动缩进的,如下图:
强迫症患者简直不能忍。这时候我们就需要手动断行了,自然也就需要知道 terminal 到底有多宽了:
const figures = require('figures') // 上面讲过 const cliWidth = require('cli-width') const stringBreak = require('string-break') // 下面会讲 function format(str) { const width = cliWidth() - 14 return stringBreak(str, width) .map((line, index) => { const icon = index === 0 ? figures.heart : ' ' return ` ${icon} ${line}` }) .join('\n') } const list = [ '我来到 你的城市 走过你来时的路....', // 省略文本 '熟悉的那一条街 只是没了你的画面....', '在街角的咖啡店 我会带着笑脸....', '不再去说从前 只是寒暄....', ] console.log() list.forEach((item) => { console.log(format(item)) }) console.log()
这是我的解决方案,如果你有更好的方法,欢迎留意交流
3.2. string-break#
项目地址:https://github.com/keenwon/string-break
我们接着上一段说,当知道 terminal 宽度后,就需要截断字符串,string-break 就是做这件事的,支持中英文混合:
const stringBreak = require('string-break') const str = '远处海港传来阵阵船笛 我一直飘零到被你拣起 如今望著反映窗户玻璃 有个我陌生又熟悉' let lines = stringBreak(str, 30) /** * lines: [ * '远处海港传来阵阵船笛 我一直飘', * '零到被你拣起 如今望著反映窗户', * '玻璃 有个我陌生又熟悉' * ] */
3.3. string-width#
项目地址:https://github.com/sindresorhus/string-width
如果你想知道一个字符串在 terminal 里占据的宽度,可以直接使用 string-width,上面介绍的 string-break 也依赖了 string-width,看示例:
const stringWidth = require('string-width') stringWidth('古') //=> 2 stringWidth('\u001b[1m古\u001b[22m') //=> 2 stringWidth('a') //=> 1
上面的第二个例子是加粗的"古"字,使用刚才介绍 chalk 可以轻松实现。如果你想了解更多细节,可以阅读ANSI 转义序列。
3.4. clear#
项目地址:https://github.com/bahamas10/node-clear
clear 是个 terminal 清屏工具,类似于使用 clear 命令或者 Ctrl + L
快捷键。
const clear = require('clear') let count = 1 setInterval(() => { count++ if (count % 5 === 0) { clear() } else { console.log(count) } }, 500)
count
整除 5 的时候清屏,执行后看起来是这样的:
3.5. debug#
项目地址:https://github.com/visionmedia/debug
debug 是个非常有用的调试库,可以通过环境变量指定输出哪些日志,express 内部就集成了 debug。
我们用 exporess 来做个简单的演示,安装 express,新建 index.js
,内容如下:
var express = require('express') var app = express() app.get('/', function (req, res) { res.send('Hello World') }) app.listen(3000)
然后执行 DEBUG=express:* node index.js
:
3.6. update-notifier#
项目地址:https://github.com/yeoman/update-notifier
update-notifier 是个更新提示工具,当你通过 npm 发布新版本后,update-notifier 会检查到更新并提示用户升级。npm 的更新提示也使用的是 update-notifier。
它的大致工作流程是这样:你的程序每次运行都需要调用 update-notifier,第一次调用时,它会异步检查是否存在可用更新,并将检查结果保存在本地;第二次运行的时候,会读取上次保存的结果,如果有可用更新,则提示给用户。
我们通过 co 来做个测试,index.js
内容如下:
const updateNotifier = require('update-notifier') updateNotifier({ pkg: { name: 'co', version: '1.0.0', // 假设现在使用的是 1.0.0, co 最新版本是 4.x }, updateCheckInterval: 1000, // 检查间隔设置 1s,方便测试 }).notify() // 延迟三秒,给 update-notifier 留时间检查 // 实际使用的时候不需要 setTimeout(() => { console.log('test') }, 3000)
4. 配置文件#
4.1. cosmiconfig#
项目地址:https://github.com/davidtheclark/cosmiconfig
实现一个 cli 工具,常常需要读取一些配置文件。例如当使用 eslint 的时候,可以把配置文件写在 .eslintrc.js
或者是 .eslintrc.json
,如果你特别喜欢 YAML,也可以用 .eslintrc.yml
cosmiconfig 是个强大的配置加载工具,可以重多个位置尝试读取配置。假设你的模块叫做 soursocks
, cosmiconfig 会从尝试搜索下列位置:
package.json
中的soursocks
属性- JSON 或者 YAML 格式的
.soursocksrc
.soursocksrc.json
文件.soursocksrc.yaml
,.soursocksrc.yml
, 或者.soursocksrc.js
文件soursocks.config.js
输出的 js 对象
stylelint、husky 等常用的工具,都是使用 cosmiconfig 加载配置文件的。需要的话可以详细看下它的文档。
4.2. js-yaml#
项目地址:https://github.com/nodeca/js-yaml
如果你需要自己解析 YAML 文件,可以使用 js-yaml,这里就不做过多介绍了。
4.3. ini#
项目地址:https://github.com/npm/ini
还有一种 ini 格式的配置文件,前端领域貌似用的不多,如果需要的话,可以看下 npm 实现的 ini。
5. 参数解析和提示#
前面介绍了很多各式各样的工具,但是最重要的,是要正确解析用户的输入,并给出相应的提示和帮助信息,例如 eslint:
$ eslint eslint [options] file.js [file.js] [dir] Basic configuration: --no-eslintrc Disable use of configuration from .eslintrc.* -c, --config path::String Use this configuration, overriding .eslintrc.* config options if present --env [String] Specify environments --ext [String] Specify JavaScript file extensions - default: .js --global [String] Define global variables --parser String Specify the parser to be used --parser-options Object Specify parser options Specifying rules and plugins: --rulesdir [path::String] Use additional rules from this directory --plugin [String] Specify plugins --rule Object Specify rules Fixing problems: --fix Automatically fix problems --fix-dry-run Automatically fix problems without saving the changes to the file system
要实现这样的功能,有很多库供你选择,例如 Commander、Meow、Minimist、Optimist、Yargs 等。可以说是风格迥异,各有特色。这里我没办法详细的对比它们的差异和优劣,因为太耗时间,而且没什么意义。我只使用过 Commander,它能满足我的所有需求,所我建议,如果你有用着顺手的,那么大可以继续用下去,如果你是第一使用,还是有必要好好选择一番的,可以参考一下下面这张图片:
图片来自 https://npmcompare.com/,挺有意思的网站,上面有一些同类型类库的对比,其中有些指标还是有一定参考价值的。
6. 结语#
不同环境可能有不同的效果,部分库在 windows 系统下效果很差,甚至根本不支持,应考虑优雅降级,保证主体功能可用。
文章中用到的工具:
- 环境
- 终端:Hyper
- 字体:Droid Sans Mono Slashed for Powerline
- 系统:Manjaro Linux x86_64
- 截图
- GIF:Peek
- PNG:Flameshot
实在写不动了,篇幅有限,未尽之处,欢迎交流。
Note
本文为原创文章,2018-07-09 首发于网易 KM 平台