【译】Node Cli 生态现状-The Landscape of npm Packages for CLI Apps
Node.js 是开发者编写命令行应用程序非常流行的选择。该平台丰富的生态系统拥有大量成熟的包,可以帮助创建优雅、交互式的命令行工具。
开发者面临的一个挑战是理解这个领域并选择正确的 package。有大量的库可供选择,但其中许多已经过时。一些库的开发已经停滞不前,一些已经被其维护者废弃,而许多库还没有跟上现代开发实践的步伐。本文的目的是将最流行的包进行分类,并突出其中的一些包以及它们当前的开发状态。
要快速尝试任何提到的包,可以使用以下工具:
$ npm install --global try-node-cli-packages
$ try commander
$ try meow
$ try chalk
该工具的仓库在此处可用:joeykilpatrick/try-node-cli-packages
🗒 注意
在过去的十年里,现代 JavaScript/TypeScript 开发已经发生了巨大的变化。TypeScript 日益增长的流行度和新的 Node.js 和 ECMAScript 功能的引入已经改变了常见的编程习惯。与现代 Web 开发不同,现代 CLI 开发没有每周都有新的框架和库不断涌现。相反,一个更加成熟的生态系统已经出现,但它对语言变化的适应速度较慢。
请记住,这里列出的许多最流行的库使用的编程风格略有过时。大多数主要的库都是在 2015 年 ES6 类发布之前设计的,尽管这里列出的所有库都已经将类型声明(.d.ts 文件)添加到了包中,或者已经通过 DefinitelyTyped
提供了类型,但几乎没有一个是专门考虑强类型推断的。今天,没有任何一个重要的库是使用 TypeScript 重写的。
此外,不要过于看重每个包的每周下载量。这些指标不应被视为开发人员偏爱的指标。包含在一个重要的包中可能会严重扭曲下载量。例如,本周有 2200 万次的 arg 下载。然而,流行的 ts-node 包将 arg 作为依赖项,本周已经下载了 1900 万次。
这里的许多包都有权衡。有些优先考虑速度,有些优先考虑包大小,有些优先考虑开发者体验。只有您可以选择最适合您需求的库。
🤝 主要贡献者
虽然有数百名贡献者为这些库做出了贡献,但有些人名字不断出现,他们是这个领域的创建者、维护者和贡献者。考虑在 GitHub 上赞助他们的开源工作。我没有任何关联。在下面的列表中,带有这些用户大量贡献的包将标有相应的表情符号。
sindresorhus 🦄
Sindre Sorhus 负责许多用于终端输出样式的的包。除了知名的包如 chalk
和 meow
之外,他还编写了许多由其他主要包内部使用的包,例如 cli-cursor
(由 inquirer
、ora
和 ink
使用)和 supports-color
(由 mocha
、nodemon
和 serverless
使用)。
lukeed 🐒
Luke Edwards 是多个轻量、性能优化的 CLI 库的作者。他的 kleur
是 chalk
的轻量级替代品,主要由 prompts
使用。他的 mri
是 minimist
的高速替代品。
Qix- 🦀
Qix 是 arg
的创建者,是 Sindre Sorhus 的频繁合作伙伴,两个用户都在 chalk
GitHub 组织中共同编写包。
参数解析
这些库构成了大多数 CLI 应用程序的基础。其中一些包将自己风格化为“参数解析器”,一些则称为“CLI 助手”,但在它们的核心,它们都帮助开发人员声明应用程序所期望的参数、命令和标志,并自动解析通过 process.argv
提供的参数。通常,开发人员只需要其中一个就足够了。
Package | Version | Downloads | Last Publish | First Publish | Types |
---|---|---|---|---|---|
commander | 10.0.0 | 109 M | 3 days ago | August 2011 | Includes .d.ts |
yargs-parser | 21.1.1 | 79 M | 6 months ago | January 2016 | DT Types |
yargs | 17.6.2 | 77 M | 2 months ago | November 2013 | DT Types |
minimist | 1.2.7 | 53 M | 3 months ago | June 2013 | DT Types |
nopt | 7.0.0 | 25 M | 3 months ago | March 2011 | DT Types |
arg🦀 | 5.0.2 | 22 M | 7 months ago | October 2017* | Includes .d.ts |
meow🦄 | 11.0.0 | 18 M | 3 months ago | October 2014 | Includes .d.ts |
mri🐒 | 1.2.0 | 7 M | 1 year ago | April 2017 | Includes .d.ts |
sade🐒 | 1.8.1 | 1.9 M | 1 year ago | May 2017 | Includes .d.ts |
📦 commander、sade、yargs
这些是开箱即用(opinionated)的软件包,它们都使用链式方法的流式界面来描述 CLI 应用程序。它们都自带自动生成的帮助文本和其他有用的功能。由于“流式”接口,对于标志和参数的强类型推断的可能性受到限制。
这个列表中最老的软件包是 commander
,它被 webpack-cli
和 babel-cli
等 CLI 应用程序使用。这个无依赖库非常大且功能丰富,有很多文档。该项目的开发仍在活跃,经常发布新功能,对 GitHub 上的问题和 PR 有非常高的响应率。
sade
是一个比 commander
更快、更轻量级的替代品。它的软件包大小为 31.5 KB,而 commander
的大小为 174 KB,它提供了所有相同的核心功能,几乎相同的界面。该项目的开发不再活跃,但它仍然可以作为 commander
的更简单的替代品。
另一个类似的软件包是 yargs
,被 CLI 应用程序如 mocha
和 nyc
使用。它的一个优点是支持多种不同语言环境中的消息。尽管比 commander
更大,达到了 290 KB,但它并没有提供更多的功能。语法还更多地依赖于嵌套的回调式箭头函数,这可能对某些开发人员来说不太易读。
📦 meow
作为上述软件包的替代品,meow
是一个更小的,非开箱即用的软件包。它使用声明式界面来定义预期的标志,而不是上述软件包中使用的“流式”界面。由于这种声明式风格,对于类型推断来说,它比上述所有软件包的推断都要强。它附带了一些有用的功能,例如自动版本和帮助标志,并为开发人员提供了很大的灵活性。它也是最早仅作为 ES 模块提供的软件包之一。它的存储库仍在活跃,但新版本主要限于维护和修复漏洞。
📦 minimist、yargs-parser、mri、nopt、arg
对于希望获得最大程度控制的开发者来说,这些包是最基本的参数解析器。它们的范围仅限于解析提供的标志和参数。虽然它们都包括标志别名的功能,但这些包通常甚至不包括所需标志、意外标志、默认标志值或帮助信息等功能。解析后的标志的类型推断几乎不存在,大多数被定义为 any 类型。这些包中的大多数已不再积极开发,并被认为已经完成。
minimist
包是现已停用的 optimist
包的参数解析器。
yargs-parser
包是 yargs
和 meow
的底层参数解析器,自称是 minimist
的继承者。它的大小为 128 KB,比本节中的其他解析器要大得多,并具有丰富的功能(有人可能会说它有些臃肿)。它直接被流行的 CLI 应用程序如 mocha
和 ts-jest
使用。
mri
包是 minimist
和 yargs-parser
的超快、轻量级替代品,具有相同的接口。它的大小约为 yargs-parser
的 10%。它也是 sade
包的底层解析器。
在前三个包中接口的另一个选择可以在 nopt 包中找到,它是由 npm 为 npm 包开发的。它具有多个额外类型的标志值,如“path”或“stream”值的特性。它还以不同的方式支持标志别名,这可能有助于某些开发者编写更具表现力的标志别名。
arg
包具有类似于 nopt
的接口,但更加精简。它被 ts-node
使用。
输出样式化
这些库允许开发者操控终端输出的展示方式。它们添加了字符串格式化、颜色以及小的基于文本的动画效果。
Package | Version | Downloads | Last Publish | First Publish | Types |
---|---|---|---|---|---|
ansi-styles🦄🦀 | 6.2.1 | 232 M | 3 months ago | July 2013 | Includes .d.ts |
chalk🦄🦀 | 5.2.0 | 189 M | 1 month ago | August 2013 | Includes .d.ts |
wrap-ansi🦄 | 8.0.1 | 70 M | 1 year ago | August 2015 | DT Types |
ansi-escapes🦄 | 6.0.0 | 31 M | 4 months ago | August 2015 | Includes .d.ts |
kleur🐒 | 4.1.5 | 17 M | 7 months ago | November 2018 | Includes .d.ts |
ora🦄 | 6.1.2 | 16 M | 7 months ago | March 2016 | Includes .d.ts |
boxen🦄 | 7.0.1 | 12 M | 1 month ago | December 2015 | Includes .d.ts |
listr | 0.14.3 | 2 M | 4 years ago | June 2016 | DT Types |
📦 chalk、kleur、ansi-styles...
有许多包专门为终端文本提供颜色和格式。该过程包括向文本中插入 ANSI 转义序列,以告知终端文本应如何格式化。有许多不同的终端实现和很多需要考虑的边缘情况。
这些包中最著名的是 chalk
,它是 npm 上依赖最多的包之一,有超过 90,000 个依赖包。它易于使用、维护得非常好,并且非常可靠。
多年来,类似于 chalk
的包已经被开发、分支和重新命名,导致许多不同的包几乎都做同样的事情。与 chalk 的竞争对手包括 colors
、picocolors
、ansi-colors
、colorette
、kleur
和 nanocolors
。这些其他包的历史非常疯狂。
在这里列出的包中,只有 colors
早于 chalk
。它在 2022 年 1 月被其所有者恶意破坏,为许多工具造成了广泛的问题。(article, article, article, owner’s manifesto)。该包被 npm 回滚,并暂停了作者在 GitHub 上的帐户( was suspended from GitHub.)。由于他是 colors 包的唯一维护者,因此该包已被实际上废弃。在此之后,许多依赖包切换到了 chalk
。
尽管不如 colors
灾难令人惊诧,但在其他 chalk 替代方案中也有很多开源社区中的戏剧。例如,考虑 2018 年 8 月 ansi-colors 和 colorette 维护者之间的冲突(this August 2018 clash ),或 2021 年 9 月 colorette 和 nanocolors 维护者之间的灾难(并得到了 chalk 维护者的参与)。
试图改进chalk的人们已经尝试创建更快、更小或具有较少依赖性的替代品。在这些尝试中,作者们已经删除了一些功能、错过了一些边缘情况,有时也会引入错误和内存泄漏。多位作者已经使用自己的基准发布了比较自己创建的替代品和chalk的度量标准。但是,如果它们不涵盖相同的边缘情况并包含相同的功能集,那么这些软件包之间的真正的同类比较是不可能的。与此同时,chalk一直在改进,现在更快(自v3起)、更小(自v5起)且无依赖(自v5起)。
对于大多数大小的软件包,都应该使用 chalk。对于需要更小的软件包尺寸和更少功能的用户,可以考虑使用 kleur,这个包经过良好的维护且非有争议性。对于只需要最基本功能的用户,可以考虑来自 chalk 作者的新 yoctocolors 包,它只有 7.6 KB 的极小尺寸。
对于需要对 ANSI 转义代码进行非常细粒度控制的软件包,ansi-styles 由与 chalk 相同的维护者维护,并具有较低级别的接口,允许开发人员在文本中插入单个 ANSI 代码。
📦 ora
ora包提供了终端的可控旋转动画。通过cli-spinners包,提供了大量的旋转动画,但也可以自定义动画。该包提供的接口非常适合常见的用例,比如显示可能成功或失败的操作进度。
📦 boxen,wrap-ansi
这些包帮助格式化终端文本块。要将文本换行到特定的列数,请使用wrap-ansi。要在文本周围绘制框,请使用boxen。它内置了许多不同类型的边框。
用户输入
Node.js提供了通过process.stdin
和readline
获取用户键盘输入,但直接使用这些方法有一定的挑战性。有多个包可用于在控制台中输出提示并等待用户输入。一些专门用于某些常见用例的库也可用,例如password-prompt
用于将输入的内容显示为“***”,yesno
或prompt-confirm
用于用户确认。以下是一些通用的用户输入库。通常,开发人员只需要使用其中的一个。
Package | Version | Downloads | Last Publish | First Publish | Types |
---|---|---|---|---|---|
inquirer | 9.1.4 | 26 M | 3 months ago | May 2013 | DT Types |
prompts🐒 | 2.4.2 | 20 M | 1 year ago | February 2018 | DT Types |
enquirer | 2.3.6 | 13 M | 3 years ago | August 2016 | Includes .d.ts |
promptly | 3.2.0 | 1 M | 2 years ago | January 2013 | DT Types |
readline-sync | 1.4.10 | 900 K | 4 years ago | August 2013 | DT Types |
prompt | 1.3.0 | 600 K | 9 months ago | March 2011 | DT Types |
📦 inquirer, prompts, enquirer
这三个包有类似的接口,并对常见的提示类型有内置支持。它们在接口中使用了一些稍有不同的术语(例如 default
与initial
,或title
与name
),有时会以意想不到的方式表现得不同。例如,当用户按下 CTRL+C 序列时,inquirer 会立即杀死进程,enquirer 会抛出一个错误,而 prompts 会取消提示但继续执行而不出错。此外,这三者都有一些明显错误的类型,使使用 TypeScript 开发变得困难。
inquirer
包是三者中最古老的,按下载量和依赖包的数量计算,它拥有最大的市场占有率。它通过其他第三方软件包(如 inquirer-autocomplete-prompt、inquirer-directory 和 inquirer-checkbox-plus-prompt)注册自定义提示类型的能力得到加强。它的作者仍在积极开发,自 2018 年以来一直在进行全面重构。
prompts
拥有最准确的类型声明,并计划进行全面的 TypeScript 重写,尽管开发已经停滞。目前,还没有简单的方法来扩展和定制提示类型。对于测试,该包允许开发人员 "注入 "提示的答案,绕过 stdin。
enquirer
包最初是为了成为 inquirer 的一个更小、更快、更好的替代品,但今天 enquirer
的大小是 inquirer
的两倍。它增加了许多额外的有用的、优雅的提示类型,如 scales
、sorts
和 snippets
。它还引入了一种使用 ES6 类来扩展和定制现有提示类型的新方法。然而,类型声明从未被添加到这个新功能中,并且该包在三年多的时间里没有看到新的发布。
📦 promptly, readline-sync, prompt
这些包不如上面的包成熟,并且几乎没有提供任何额外的功能。它们的用户界面不够优雅,并且没有内置用于常见提示类型(例如数字、列表或选择)的功能。另外,虽然 promptly
的大小仅为 15.5 KB,但其他两个与 prompts
和 enquirer
的大小大致相同。它们没有得到积极的开发或维护,新项目中可能不应该使用它们。
框架
上面所有的软件包都是为了处理 CLI 开发的一个特定方面。然而,还有一些软件包并不适合上述任何类别,它们的目的是为开发者提供一整套工具来构建他们的 CLI 应用。
Package | Version | Downloads | Last Publish | First Publish | Types |
---|---|---|---|---|---|
@oclif/core | 2.0.8 | 794 K | 5 hours ago | February 2018* | Native |
ink🦄 | 3.2.0 | 283 K | 1 year ago | July 2017* | Native |
vorpal | 1.12.0 | 39 K | 6 years ago | August 2015 | DT Types |
📦 oclif
在2018年,Salesforce宣布开源了他们构建一些CLI应用程序(例如Heroku CLI)的oclif框架。这是一个庞大而分散的框架,具有插件、自动生成脚手架、内置测试工具等功能。它有很强的意见色彩,类似于大型web框架,如Angular或React。
对于具有许多git样式子命令的巨型CLI应用程序,oclif是一个杰出的选择。对于较小的CLI应用程序,它可能过于复杂。
📦 ink
与本文中列出的所有其他软件包基本上是不同的范例,ink允许开发人员定义React组件,然后在终端上呈现这些组件。与需要格式化和打印单个字符串的文本输出不同,ink允许用户定义反应性XML组件,这些组件在用户的终端中重复绘制。表达能力很强的界面允许开发人员定义多行终端动画,否则这些动画将非常复杂和脆弱。
在这个列表中的所有软件包中,我认为这个最惊人。这个软件包的概念和执行都非常令人印象深刻。这个软件包重新定义了终端输出和CLI用户体验的可能性。
📦 vorpal
大多数CLI应用程序都遵循相同的执行模型:用户运行终端命令,然后生成一个进程,该进程解析提供的参数和选项,执行某些操作,然后关闭。vorpal软件包采用非常不同的方法,将其方法命名为“沉浸式”。当运行vorpal应用程序时,其进程打开一个新的子终端,允许用户输入进一步的应用程序特定命令。这种应用程序可以不视为一组孤立的命令,而是作为整个shell的实现。这种新范例带来了一整套新的可能性。先前命令设置的变量可以由后续调用访问。应用程序可以支持自动完成命令。用户可以将命令连接在一起。定义子命令的代码使用与commander和其他软件包相同的“流畅”接口风格,具有相同的缺点。
虽然这种方法是新颖的,但它未能获得显着的使用和发展。vorpal项目于2018年被放弃。试图fork和“重铸”它的努力也于2019年被放弃。cliffy软件包似乎受到vorpal的启发,正在进行一定程度的开发,但它甚至比vorpal不成
转载自:https://juejin.cn/post/7218080084140965948