Awesome Command-line Utilities

2018-07-09 · 48 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

实在写不动了,篇幅有限,未尽之处,欢迎交流。

本文为原创文章,2018-07-09 首发于网易 KM 平台