1 Star 3 Fork 0

Jay_Ohhh / front-end notes

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
命令行工具.md 11.33 KB
一键复制 编辑 原始数据 按行查看 历史
Jay_Ohhh 提交于 2022-06-23 15:31 . update

开发前端 CLI 脚手架思路解析

开发一个 Node.js 命令行工具包

package.json

scripts

脚本指令,在这里可以自定义一些指令。

npm 脚本的原理非常简单。每当执行 npm run,就会自动新建一个 Shell,在这个 Shell 里面执行指定的脚本命令。因此,只要是 Shell(一般是 Bash)可以运行的命令,就可以写在 npm 脚本里面。

比较特别的是,npm run 新建的这个 Shell,会将当前目录的 node_modules/.bin 子目录加入 PATH 变量,执行结束后,再将 PATH 变量恢复原样。

推荐阅读:npm scripts 使用指南

bin

我们的项目所提供的自定义指令,以及对应的可执行文件的映射地址:

{
  ...
  "bin": {
    "demo-cli": "bin/demo-cli"
  },
  ...
}

当我们的自定义指令的名字就是项目名称的时候,可以简写为以下形式:

{
  ...
  "bin": "bin/demo-cli",
  ...
}
bin 命令是如何运行的
Linux bin 目录的作用

shell 任务的一个重要部分是搜索命令。Bash 是按照下一的步骤来完成的:检查命令是否包含斜杠。如果没有,首先检查函数列表是否包含一个我们寻找的命令。如果命令不是一个函数,那么在内建命令列表中检查。shell 内建命令是指 bash(或其它版本)工具集中的命令。一般都会有一个与之同名的系统命令,比如 bash 中的 echo 命令与 /bin/echo 是两个不同的命令,尽管他们行为大体相仿。当在 bash 中键入一个命令时系统会先看他是否是一个内建命令,如果不是才会查看是否是系统命令或第三方工具。所以在 bash 中键入 echo 命令实际上执行 bash 工具集中的 echo 命令也就是内建命令,而不是 /bin/echo 这个系统命令。

备注:Linux 中的 type 命令如果命令既不是函数也不是内建命令,那么扫描列在 PATH 中的目录列表来进行查找。

通常如果我们要在 Linux 中执行自定义脚本,那么我们需要通过路径的形式来执行相应的文件,如果我们在 PATH 里的目录中注册了相应的指令或者通过 alias 对这个路径起了别名的话,就不需要输入完整路径。

linux 或者 MacOS 中的 bin 目录一般是用来存放可执行命令的文件夹,通常有:

  • /bin
  • /sbin
  • /usr/bin
  • /usr/local/bin
  • /usr/sbin
  • ...

要具体了解这些目录里有哪些指令,可以参考这篇文章:bin 目录简单区别

node bin

首先,我们需要找到我们的 node 的安装地址,这个可以通过在 Linux、MacOS 或者 VSCode 的终端里输入一下指令来获得:

echo $PATH

这会打印出当前所配置的环境变量,一般我们安装 node 的时候会自动在 PATH 里加入

图片

如上图所示,其中 “/Users/hopewlliu/.nvm/versions/node/v14.17.3/bin” 便是本电脑 node 中所有所有全局指令所在位置。

以下为当前电脑的全局指令、软连接的指令及其所映射的文件地址:

图片

软链的创建方式很简单,比如我们对上图的 imserver 添加一个新的软链 imserver2,可以执行一下指令:

ln -s ../lib/node_modules/@tencent/imserver-cli/bin/imserver ./imserver2

现在我们就可以在全局上使用 imserver2 命令了,他和 imserver 的效果是一致的。

同时想要删除软连接也很简单,只需要执行以下指令即可:

rm ./imserver2
全局安装与非全局安装

全局安装

如果我们通过 -g 的形式来安装一个包的话,他会被安装到 node 相关文件夹中,在本文即为:

“/Users/hopewlliu/.nvm/versions/node/v14.17.3/lib/node_modules”

目录下,如果该包的 package.json 中存在 bin 字段的指令配置,同时会在:

“/Users/hopewlliu/.nvm/versions/node/v14.17.3/bin”

目录下创建相应的指令软链。

非全局安装

非全局安装的包存在于我们的项目的根目录的 node_modules 目录下,如果该包存在自定义指令,那么会在安装包的时候在当前项目的根目录的 node_modules/.bin 目录下添加相应的自定义指令的软链接,想要执行这个包的自定义指令,我们可以直接通过路径的形式来找到该包指令所在位置然后执行,但是通常的做法是在当前的项目的 package.json 中添加相应的 npm scripts 来执行

原理就是 npm scrpits 在执行的前一刻会开启新的 shell 并把当前项目的根目录的 node_modules/.bin 目录加入 PATH 环境变量中,然后在这个 shell 中执行自定义的脚本指令,并在执行完成之后将 PATH 恢复原样。

目标文件的执行原理

解释完指令的寻找与执行后,我们需要探讨一下相应的脚本是如何被执行的,通常我们写的自定义脚本文件的入口文件的固定第一行都需要写上一行代码:

#!/usr/bin/env node

#! 被称为shebang,它告诉系统其后路径所指定的程序即是解释此脚本文件的 shell 解释器,比如我们在写自定义 shell 脚本的时候可以在脚本的第一行指定当前脚本所使用的解释器:

  • #!/bin/bash
  • #!/bin/zsh
  • ...

这样写的目的是为了使该文件以可执行程序去运行的时候可以找到相应的解释器,当然如果将文件所在位置作为参数传递给解释器来执行的话,则不需要在自定义脚本的第一行添加上述代码(写了也没用),例如:

  • /bin/bash ./test.sh
  • ...

说了这么多,那么我们的 **“#!/usr/bin/env node“**又有什么不同呢?

#!/usr/bin/env <executableName> 是一种可移植指定解释器的方式:简而言之,它表示:执行 <executableName>

说白了就是告诉系统,当前的脚本需要通过 node 来执行,node 解释器所在位置需要在 $PATH 环境变量中所列举的目录中去寻找。

因此此文件就可以默认通过 node 来执行,并且我们也可以省略文件的后缀名(或者写啥后缀都行),与此同时也不需要我们显式的通过指定 node 解释器以文件路径作为参数的形式来执行,也就是类似于以下方式:

  • node ./test.js
  • ...

常用包

  • chalk[1] (控制台字符样式)
  • commander[2] (实现 NodeJS 命令行),例如 node -v 的 -v ,打印版本号
  • download[3] (实现文件远程下载)
  • fs-extra[4] (增强的基础文件操作库)
  • handlebars[5] (实现模板字符替换)
  • inquirer[6] (实现命令行之间的交互)
    • inquirer-autocomplete-prompt 输入字母自动查找选项
    • inquirer-maxlength-input-prompt 输入最大值
  • log-symbols[7] (为各种日志级别提供着色符号)
  • ora[8] (优雅终端 Spinner 等待动画)
  • update-notifier[9] (npm 在线检查更新)
  • shelljs —— 常用的 shell 命令支持
  • debug —— 类似于 chalk
  • execa —— 执行 shell 指令
  • rimraf —— The UNIX command rm -rf for node.
  • glob —— Match files using the patterns the shell uses
  • listr2 —— 管理执行任务,支持串行、并行
  • pkg-install —— 在js中安装npm依赖包
  • console-clear —— 清除 console,可保留历史
1
https://gitee.com/Jay_Ohhh/front-end-notes.git
git@gitee.com:Jay_Ohhh/front-end-notes.git
Jay_Ohhh
front-end-notes
front-end notes
master

搜索帮助