从浅入深讲解 Node 如何开发一个命令行工具

开发 开发工具
最初印象大致是 ls,pwd 这些能够在终端执行的系统命令,这样的命令有很多,数不胜数,被称为系统内置命令。

 [[379960]]

最近山月开发了一个从任意 URL 解析内容并生成 markdown 的小客户端工具: markdown-read。用以我个人公众号的内容获取及一些优质内容的整理收藏,欢迎 Star、下载及使用。

  1. $ markdown https://juejin.cn/post/6924258563862822919 | head -10 
  2. > 本文作者:Wind、Skyler、ZRJ、ZJ 
  3.  
  4. ## 前言 
  5.  
  6. Webpack5 在 2020 年 10 月 10 日正式发布,并且在过去的几个月中快速演进和迭代,截止 1 月 28 日,Webpack5 已经更新了 18 个 minor 版本,带来了许多十分吸引人的新特性。据[官网介绍](https://webpack.js.org/blog/2020-10-10-webpack-5-release/#general-direction "官网介绍"),Webpack5 整体的方向性变化有以下几点: 
  7.  
  8. ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/77ee2267bfa34ef5bf7bb29553a5035c~tplv-k3u1fbpfcp-zoom-1.image) 
  9.  
  10. +   通过持久化硬盘缓存能力来提升构建性能 
  11. +   通过更好的算法来改进长期缓存(降低产物资源的缓存失效率) 

想到用 Node 开发一个命令行工具在工作中也较为常见,也很有意思,总结一下

命令行工具

什么是命令行工具?

最初印象大致是 ls,pwd 这些能够在终端执行的系统命令,这样的命令有很多,数不胜数,被称为系统内置命令。如果使用 which 查看他们的来历,则能够发现他们的庐山真面目:

  1. $ which pwd 
  2. pwd: shell built-in command 

随着对 Linux/Unix 系统理解及使用的逐渐加深,发现了诸多的非内置命令:

  • top
  • ps
  • netstat
  • dig
  • man

使用 which 侦查情况,发现他们实际执行的路径在某一个 bin 目录

  1. $ which top 
  2. /usr/bin/top 
  3.  
  4. $ which ps 
  5. /bin/ps 

而这些 bin 目录在环境变量 PATH 中,豁然开朗。简而言之: 在 PATH 中路径的命令可在其它任意地方执行。

  1. export PATH=$HOME/bin:/usr/local/bin:$PATH 

你好像想起点什么?在大学配置 Java 时被环境变量支配的各种恐惧?是了,所有语言的可执行命令都要放在 PATH 下,只不过其它语言自动给你做了,而 Java 让你自己做这件事。

  • java
  • python
  • pip
  • node
  • npm

开发命令行的原理也是如此,而本篇文章的目标就是:

使用 Javascript 这门前端开发者熟悉的语言,借助 Node 环境,开发一个命令行工具。

原理

先看两个命令行工具: serve 一个流行的静态文件服务器,markdown 一个我自己写的解析 URL 到 markdow 的命令行。通过命令解析出他们指向的符号链接

  1. $ ls -lah $(which serve) 
  2. lrwxr-xr-x  1 xiange  admin    65B  7 12  2020 /usr/local/bin/serve -> ../../../Users/shanyue/.config/yarn/global/node_modules/.bin/serve 
  3.  
  4. $ ls -lah $(which markdown) 
  5. lrwxr-xr-x  1 xiange  admin    48B  1 28 20:06 /usr/local/bin/markdown -> ../lib/node_modules/markdown-read/md-read-cli.js 

从中可以看出他们关于命令行的解析:

  1. npm 全局下载 Package 到 /usr/local/lib/node_modules 下 (yarn 同理)
  2. 根据 package.json 中 bin 选项的指示,对应的二进制脚本挂载到 PATH 路径
  3. 对应的二进制脚本添加 x 权限 (可执行文件权限)

简而言之,Node 环境下的命令行工具,借助的原理无非是环境变量 Path 与一个符号链接

从 package.json 说起

在 package.json 中的 bin 选项,用以指定最终的命令行工具的名字

  1.   "bin": { 
  2.     "markdown""./md-read-cli" 
  3.   } 

如上所示,markdown 是最终在终端执行的命令,而 ./md-read-cli 是该命令实际执行的文件。

对于最终可执行的命令行工具,Node 项目一般倾向置文件于 bin 目录下,如以下 Typescript 的配置:

  1.   "bin": { 
  2.     "tsc""./bin/tsc"
  3.     "tsserver""./bin/tsserver" 
  4.   }, 

一个执行环境

对于可直接执行的文件,需要指明执行环境,首行添加一行说明:

  1. #!/usr/bin/env node 
  2.  
  3. // code 往下写 

这一句话是啥子意思了?

  1. #! 后接解释器,标明该文件使用 /usr/bin/env node 来执行
  2. /usr/bin/env 为 env 的绝对路径,用以在 PATH 路径中执行命令 (在各种不同的系统中,node 命令行的位置不同,因此使用 env node 找到路径并执行)
  3. env node 在人为层面可理解为执行 node 命令

所以这句话的意思是: 使用 node 执行这个脚本

  1. // 不写 #!/usr/bin/env node 
  2. $ node serve . 
  3.  
  4. // 写上 #!/usr/bin/env node 
  5. $ serve . 

解析命令输入

  1. $ node cmd.js 1 2 3 
  2. // Output: [ 
  3. //   '/usr/local/bin/node'
  4. //   '/Users/shanyue/cmd.js'
  5. //   '1'
  6. //   '2'
  7. //   '3'
  8. // ] 
  9. process.argv 

根据解析 process.argv 来获取各式各样的参数作为命令行的输入,当然解析参数也要参照基本规律: 格式、可选、必选、简写、说明、帮助等等。命令行工具命名协议 文章中已说的足够详细。

  1. // 一个较为规整的命令行帮助 
  2. $ node --help 
  3. Usage: node [options] [ script.js ] [arguments] 
  4.        node inspect [options] [ script.js | host:port ] [arguments] 
  5.  
  6. Options: 
  7.   -                                         script read from stdin (default if no file name is provided, 
  8.                                             interactive mode if a tty) 
  9.   --                                        indicate the end of node options 
  10.   --abort-on-uncaught-exception             aborting instead of exiting causes a core file to be generated for 
  11.                                             analysis 
  12.   -c, --check                               syntax check script without executing 
  13.   --completion-bash                         print source-able bash completion script 
  14.   --cpu-prof                                Start the V8 CPU profiler on start up, and write the CPU profile to 
  15.                                             disk before exit. If --cpu-prof-dir is not specified, write the profile 
  16.                                             to the current working directory. 

以此衍生出了关于解析命令参数的多个库,在实际工作中就直接用吧!

  • yargs: Star 8.5K,周下载量 4900K
  • commander: Star 19.7K,周下载量 5300K,tj 大神的作品

使用 commander 解析不同的输入指令

  1. const { program } = require('commander'
  2.  
  3. // 解析不同的指令输入 
  4. program 
  5.   .option('-d, --debug''output extra debugging'
  6.   .option('-s, --small''small pizza size'
  7.   .option('-p, --pizza-type <type>''flavour of pizza'
  8.  
  9. program.parse(process.argv) 
  10.  
  11. const options = program.opts() 
  12. console.log(options) 

丰富的色彩体验

Next 构建输出

目前大部分终端已支持彩色输出,丰富的高亮色彩如同代码高亮一样使用户可以快速抓住重点。把异常、警告、成功的信息用不同的颜色标出,命令行工具的输出一目了然。在现代构建工具,如 Webpack 下,也大都支持彩色输出。

以下是在命令行工具中常用的两个色彩库,支持多种多样色彩的输出。

  • chalk
  • colors

以下是 chalk 示例,Error 与 Warning 信息用不同的颜色表示

  1. const chalk = require('chalk'
  2.   
  3. const error = chalk.bold.red 
  4. const warning = chalk.keyword('orange'
  5.   
  6. console.log(error('Error!')) 
  7. console.log(warning('Warning!')) 

发布与安装

在辛苦努力写完一个 cli 工具后,就是检验成果的时候。发布到 npm 仓库,可使所有人使用你的命令行工具,这也是最重要的一步

  1. # 发布之前需要 npm login,登录到 npm registory 
  2. $ npm publish 

发版成功后全局下载命令行工具,开始使用,示例用它抓取下我的博客首页

  1. $ npm i -g markdown-read 
  2. /usr/local/bin/markdown -> /usr/local/lib/node_modules/markdown-read/md-read-cli.js 
  3. + markdown-read@1.1.0 
  4. added 102 packages from 72 contributors and updated 10 packages in 33.15s 
  5.  
  6. $ markdown https://shanyue.tech 
  7. ## [#](#山月的琐碎博客记录) 山月的琐碎博客记录 
  8.  
  9. 本博客关于平常工作中在前端,后端以及运维中遇到问题的一些文章总结。以后也会做系列文章进行输出,如前端高级进阶系列,个人服务器指南系列。个人微信 shanyue94,欢迎添加交流 
  10.  
  11. ## [#](#名字由来) 名字由来 

总结

本篇文章由浅至深讲解了以下几方面的内容:

  1. 一个全局可执行的命令行工具的原理是什么
  2. 在 Node 中开发一个命令行工具所需要的配置
  3. 开发命令行工具时如何解析参数

并根据实践,开发了一个从 URL 中读取 Markdown 的小工具: markdown-read,欢迎 Star、下载及使用。

另外,我基于此命令行做了一个 Web 版,欢迎来体验: https://devtool.tech/html-md

本文转载自微信公众号「全栈成长之路」,可以通过以下二维码关注。转载本文请联系全栈成长之路公众号。

 

责任编辑:武晓燕 来源: 全栈成长之路
相关推荐

2019-06-10 15:00:27

node命令行前端

2020-12-11 06:44:16

命令行工具开发

2020-12-10 16:16:08

工具代码开发

2019-05-30 10:40:04

ddgrLinuxDuckDuckGo

2011-06-17 16:49:05

Cocoa苹果

2016-08-10 12:41:00

Linux工具bcShell

2020-12-08 08:46:07

GoJava工具

2018-11-21 09:57:44

命令行Linux文件

2021-04-01 13:25:46

Node命令工具

2022-02-17 18:21:47

工具HTTPie客户端

2014-06-16 09:28:08

Linux命令行

2018-09-10 09:30:25

Linux命令应用

2018-05-04 09:15:35

PythonPlumbum命令行

2015-07-15 10:32:44

Node.js命令行程序

2016-09-23 20:16:23

TaskwarriorLinux命令行工具

2013-07-26 14:10:06

Linux命令行

2018-06-12 15:10:11

Linuxvim命令PacVim

2022-01-26 18:59:08

Python工具

2014-08-25 16:23:24

2018-07-05 08:30:54

Python命令行工具shell
点赞
收藏

51CTO技术栈公众号