Node CLI工具原理解析
本文为稀土掘金技术社区首发签约文章,14天内禁止转载,14天后未获授权禁止转载,侵权必究!
本文将主要介绍CLI相关周边知识
,通过本文读者可以了解到CLI的基本工作原理
,注册全局指令
的几种方式、Node CLI的基本工作原理
。
前言
CLI(Command-Line Interface) 命令行界面
搞开发的同学,或多或少的都会接触到许多的命令行工具。
有生产力工具,也有有意思的小玩意、自动化任务处理等等。
命令行工具的安装方式就很多了。
win
上大部分是通过软件安装包安装,安装同时会通过环境变量
配置相关指令。
linux
和mac
上就比较丰富了,前者常用yum
和api-get
、mac 上就brew
。
也有使用wget
和curl
拉取相关工具的shell
脚本执行安装。
说了这么多工具,都不是本文要讲的工具,前端搬砖当然首选node
,然后基于npm
做包的分发。
PS:文中的示例都以mac
为主
可执行shell
unix
系上大部分可执行文件都是基于shell
的脚本。
比如随手写个hello world
文件名hello
,内容如下
echo "Hello world"
此时我们直接执行是会提醒没有执行权限,我们为当前用户加1个可执行权限
chmod u+x hello
然后再当前目录执行,就看到输出结果了
./hello
注册全局指令
为了使“指令”在全局任意位置都能被使用,就需要做相关操作了。
环境变量
相信大多数首次接触这个词的朋友都在win
上深有体会。装JDK
、MySQL
时都避免不了有配置的操作。
如果想在其它目录直接执行hello
就生效呢?那这就离不开环境变量配置了
咱们先看终端用的shell
工具是什么。
echo $0
我这里使用的是zsh
,其它的常见的还有bash
相应的配置文件分别是.zshrc
和.bashrc
alias指令
使用 alias指令设置别名
指令格式
alias <别名>=<指令或可执行文件路径>
添加内容如下
alias hello=/Users/sugar/Documents/diy-cli/hello
立即生效配置
source ~/.zshrc
export指令
使用export命令添加添加相关目录
指令格式
export PATH=$PATH:<路径 1>:<路径 2>:<路径 N>
添加内容如下
export PATH=$PATH:/Users/sugar/Documents/diy-cli
以上2种方案都能达到目标的效果
如果每个工具都单独配一条规则。那会导致相关配置文件非常的庞大,也不方便维护。
实际上我们在用npm i -g
安装的全局包的时候,并没有手动配置。那么这个是如何做到的呢。这个就离不开下面将要说到的符号链接
了
符号链接
软链接
类似于快捷方式,它可以指向任意文件系统中的一个文件或目录;硬链接也可以看作是文件或目录的快捷方式,但源文件删除了也不影响硬链接
。
先通过which npm
看一下npm所在位置
打印一下$PATH
的值,可以看到npm
指令对应文件所在目录就在其中
展开目录内容可以看到文件类型都是l(软连接)
因此咱们可以小结出来 通过向已添加到$PATH变量中的目录,直接创建短链可以实现指令的自动注册全局
下面实践演示一下
ln指令
指令格式
# 硬链接
ln source target
# 软连接
ln -s source target
接着上面之前的例子,再使用export
完成对目录的添加后。咱们再随便建立个文件hello2.sh
进行操作
内容如下
echo "Hello world2"
创建一个软链
ln -s <source>/hello.sh <target>/hello2
操作结果如下
前面代码都是简单的写的shell
脚本
前端当然是羧js
,咱们把代码改成js。
hello.js
console.log('hello js')
按照前面的步骤,完成可执行权限添加和软链的创建。
结果可以预测是会报错的,默认会被当做shell
脚本进行执行。
那么如何指定为使用node
去执行这个文件?
这就是我们下文要说到的hashbang
Hashbang
Hashbang
(也称为Shebang
)是一个由井号和叹号构成的字符序列 #!,通常出现在文件开头,例如#!/usr/bin/env bash
用于指定脚本的运行环境
于是,我们给前面的hello.js
头部加上#!/usr/bin/env node
再次运行就成了
至此基本清楚了,如何将1个js
脚本便捷的注册为1个全局可执行指令
Node CLI
node
官配包管理工具npm
,通常每个项目中有一个package.json
文件,用于描述项目的一些信息或者包含项目相关的配置内容
指令注册
其中bin
属性用于设置指令名称
和执行脚本所在位置
{
"name":"pkgName",
"bin": {
"command": "exec/filepath.js"
}
}
使用npm install
安装依赖,会根据bin
中的描述,创建1个command
到exec/filepath.js
的软链
软链所在目录区别于是否是global
安装
这个目录可以通过npm bin
指令查看
全局路径和前面使用 which npm
获取的一致,当前项目的路径即在node_modules/.bin
中
如果是本地开发CLI时,可以使用npm link
指令根据bin
描述信息,自动创建软链到npm bin
所示的目录中,通过-g
参数区别是否是全局
# 项目工作目录下执行
npm link
# or
npm link -g
命令行参数
前面主要都在围绕命令展开介绍。要实现工具的丰富功能离不开参数的组合,本小节就介绍下Node
里如何处理Command
与Options
。
我们可以通过process.argv
方法获取到运行时的 命令行入参
console.log(process.argv);
各位置参数释义
0
:Node可执行文件所在路径1
:执行的js脚本路径>1
:用户运行时传入的参数
通过这些参数,就能区分出用户要执行的行为
当然在实际开发中大部分场景下,都会使用第三方库去解析命令行参数
,来降低代码的复杂度,提高可读性。
下面是一个使用commander
的例子
#!/usr/bin/env node
const { Command } = require('commander')
const pkg = require('./package.json')
const program = new Command()
program.version(pkg.version)
program
.command('hello [paths...]')
.description('hello world demo')
.alias('h')
.option('-p, --pkg <path>', 'set package.json path')
.action((paths, options) => {
console.log('😄😄😄');
console.log(paths);
console.log(options);
})
program.parse(process.argv)
可以看到使用第三方库辅助处理参数
,已经非常完善了
除了老牌的commander之外还有其它的相同作用的库,这里就不展开介绍了。
彩色打印
这个大家都不陌生了,大部分CLI打印结果都是五颜六色
的
比如下面的例子
echo '[36mhello world[39m'
相关知识点是ANSI Escape code
,这里就不展开说明了。
实际开发中,也很少直接写这种原始的数值。通常会使用chalk这个库辅助,比如上面这个颜色对应代码如下。
const Chalk = require('chalk');
console.log(Chalk.cyan('hello world'));
渐变色打印就常用gradient-string这个库
const gradient = require('gradient-string');
console.log(gradient('cyan', 'pink')('Hello world!'));
简单两行代码效果就出来了
终端交互
在使用 例如Vue CLI
此类工具进行项目初始化的时候,会有输入
,单选
,多选
等交互操作。
相关原理涉及内容太“抽象”,篇幅较大,后续通俗精简了再做分享
常用的第三方库就是inquirer这个库
下面是简单checkbox
示例
const inquirer = require('inquirer');
inquirer
.prompt([
{
type: 'checkbox',
message: '水果选择',
name: 'fruits',
choices: [
{
name: '🍌',
},
{
name: '🍉',
},
{
name: '🍇',
},
]
},
])
.then((answers) => {
console.log(answers);
});
最后
本文没有阐述非常深奥的知识点,只涉及日常的一些基操
,有助于读者了解Node CLI 背后的工作原理。
如内容有不妥之处,可以评论区交流;有感兴趣希望深入了解的知识点也可评论区@。
完整示例代码移步=>Github