使用NRWL-NX-workspace创建一个Node-js-命令行库
为什么要费心写另一篇关于 CLI 库的文章呢?
有无数关于创建 Node.js 命令行库的文章可用,而本文并不尝试重新发明轮子。它被作为一个统一的工作流,专门为 zhi 主题所采用并为 zhi 所使用的技术堆栈进行了量身定制:NRWL NX 工作区、语义化版本控制、GitHub actions、GitHub packages、多分发渠道(即功能/预发布分支)以及 Netlify/Vercel 服务。
在这篇文章中,我会分享我在 思源笔记 zhi 主题 开发过程中创建命令行库时精确的开发流程。这个统一的开发栈帮助我在我的各个子项目之间共享库时减少了大量重复工作和时间。
阅读本文对我有什么好处?
本文将指导您如何:
- 创建一个基于 NX 的工作区
- 在 NX 工作区中创建一个 Typescript 的 Vite 项目
- 将该项目暴露为 node.js CLI 执行项目
- 转译为 ESM 模块
- 将代码分割成命令
文章末尾有一些跟进文章:
- 使用 GitHub Actions 自动将库发布到 NPM 仓库中。
- 在开发机器上使用环境参数运行库。
一个可运行的例子可以在 terwer/zhi 中找到。
先决条件
请确保您正在使用 Node 版本 >= 16。
顺带一提,为了在您的计算机上使用多个 Node 版本,如果您未使用 nvm-sh/nvm:Node 版本管理器,我建议您尝试一下。
设置工作区
创建新的 NX 工作区。
1 | npx create-nx-workspace@latest |
当询问时,请选择选项 integrated monorepo > ts
。
create-nx-workspace 脚本会创建一个以您提供的项目名称命名的文件夹。进入新创建的文件夹。
添加 .nvmrc
文件并将内容设置为所需的 Node.js 版本号。例如,如果您正在使用 Node v16:
1 | 16 |
现在,请运行以下命令在工作区中创建一个基于 Vite 的新项目。
1 | ## Create a Vite project |
在文件 packages/zhi-cli/package.json
中:
将版本设置为
1.0.0
.让脚本可执行。
1
"bin": "./index.js"
注意:一旦部署到 NPM,您将可以使用其名称运行该库,例如通过运行 npx zhi-cli --help
。
添加一些脚本,这些脚本可以在开发过程中帮助你。注意:在根目录加,不是子项目。
1
2
3
4
5
6
7
8
9
10
11{
"name": "zhi",
"version": "1.0.0",
"license": "GPL",
"type": "module",
"scripts": {
"dev:zhi-cli": "node --experimental-specifier-resolution=node --loader ts-node/esm packages/zhi-cli/index.ts",
"watch:zhi-cli": "nx run zhi-cli:build --watch",
"cli:zhi-cli": "node --experimental-specifier-resolution=node dist/packages/zhi-cli"
},
}
注意:上面我们设置了 "type": "module"
, 这样保证直接 ESM 的方式运行 js 文件,否则就需要设置文件后缀名为 mjs。
还有:如果直接运行 ts 文件,还需要安装 ts-node
。
在文件 packages/cli/tsconfig.lib.json
中添加一个标志以避免 Typescript 错误,当库没有导出默认对象时。
1 | { |
在文件 packages/zhi-cli/project.json
中,当构建包时,您应该指示 NX 将包使用的依赖项包含在生成的 package.json 中。
1 | "targets": { |
将库转换为为 ES 模块
要导入 ES 模块库,你的库也应该是 ==ES 模块==。有关更多信息,请参见 @nrwl/node 应用程序未转换为 esm · Issue #10296 · nrwl/nx 。请通过以下步骤进行:
- 在文件
packages/zhi-cli/package.json
中添加"type": "module"
,这个在上面一步已经说过了。 - 在文件
packages/zhi-cli/tsconfig.json
中,将module
值更改为esnext
。 - 在文件
tsconfig.base.json
中,将target
编译器值更改为esnext
。
创建初始 CLI 命令
在继续指南之前,现在是将您的工作区提交到 Github 的好时机。
在前面的部分,您创建了一个工作区并准备好了您的命令。现在是添加命令的时候了。
library 的推荐结构:
1 | packages |
在本文中,我们将创建一个名为 init
的命令,除了写入控制台外,什么也不做。
安装推荐的库
许多优秀的库可被用于提供丰富且友好的命令行用户体验。
在本文中,我们将安装一些必备的库。
- commander - npm - 必备的一个库,可让您定义命令及其参数、选项、帮助等。
- debug - npm - 必备的一个流行库,可用于编写调试日志。
- fast-glob - npm - 推荐的一个高速高效的 Glob 库。
- inquirer - npm - 推荐的一个常见交互式命令行用户界面的集合。
安装所需的库(可以添加更多)。
1 | pnpm add commander debug |
添加初始命令代码
新建 src/lib/utils.ts
文件
将以下内容复制到 utils 文件中。
1 | import Debug from "debug" |
src/lib/init/command.ts
文件
请复制以下模板并根据需要进行调整。
1 | import * as fs from "fs" |
src/lib/zhi-cli.ts
文件
创建文件并添加以下内容:
1 | import { Command } from "commander" |
配置 Vite 支持 Node
这一步非常重要,否则后面的无法运行,修改 vite.config.ts
,这里需要添加 external
和 output.banner
。
1 | build: { |
测试命令
先运行 nx build zhi-cli
1 | ➜ zhi git:(dev) ✗ nx build zhi-cli |
然后运行以下命令 node --experimental-specifier-resolution=node dist/packages/zhi-cli init --verbose
。
1 | ➜ zhi git:(dev) ✗ node --experimental-specifier-resolution=node dist/packages/zhi-cli init --verbose |
或者 pnpm cli:zhi-cli
1 | ➜ zhi git:(dev) ✗ pnpm cli:zhi-cli |
运行 init
1 | ➜ zhi git:(dev) pnpm cli:zhi-cli init --verbose |
命令行测试命令
你可以以类似于部署应用的行为方式进行测试。
确保您构建了项目。
在终端中,导航到 dist/packages/zhi-cli
,然后运行 npm link
命令。
1 | cd dist/packages/zhi-cli |
完成后,您可以导航返回根文件夹。
1 | ➜ zhi-cli git:(dev) sudo npm link |
使用 npx 运行这个库。例如,npx zhi-cli
:
1 | ➜ zhi-cli git:(dev) npx zhi-cli |
NPM 测试命令
一旦部署到 NPM 仓库,您可以使用 NPX 运行它,而无需下载库。如果您的库不紧密地与使用它的库/应用程序的工作流程相关,则建议使用此方法。
1 | nx publish zhi-cli --ver=1.2.0 --tag=lates |
1 | npx zhi-cli |
结果如下:
1 | Documents npx zhi-cli |
提供用户体验良好的 UX
JavaScript 生态系统非常棒,可以通过使用其他库让你的应用程序更加出色。但是,还要记住,当你越来越多地依赖第三方库时,会增加安全漏洞的潜在可能性。
我正在使用两个库显著提高我的项目用户体验。您可以在 terwer/zhi 中查看我的使用情况。
多种配置库的方式。
有一个神奇的库 davidtheclark/cosmiconfig: 从 package.json 属性、rc 文件或 CommonJS 模块中查找和加载配置,它可以帮你完成所有繁琐的工作。
Cosmiconfig 搜索并加载程序的配置。例如,如果您的模块名为“myapp”,cosmiconfig 将在以下位置查找目录树中的配置:
- 在
package.json
文件中有一个myapp
属性 - 在 JSON 或 YAML 格式的
.myapprc
文件 - 在
.myapprc.json
、.myapprc.yaml
、.myapprc.yml
、.myapprc.js
或.myapprc.cjs
文件中有myapprc
、myapprc.json
、myapprc.yaml
、myapprc.yml
、myapprc.js
或myapprc.cjs
文件 - 在
.config
子目录内的myapprc
、myapprc.json
、myapprc.yaml
、myapprc.yml
、myapprc.js
或myapprc.cjs
文件 - 一个 CommonJS 模块
myapp.config.js
或myapp.config.cjs
导出一个对象
使用友好的界面与用户交互。
inquirer - npm 库是一个收集常见命令行交互式用户界面的集合。一些人在处理参数时会遇到困难,特别是当参数很多时。相反,他们更喜欢与库进行交互,而 inquirer 正是如此。
它在 create-react-app
、create-nx-workspace
等许多应用中都表现出色,因此它也应该适用于您。
接下来是什么?
就是这样了。您现在已经准备好添加库逻辑了。如有问题欢迎邮件 youweics@163.com 。
附加资源
阅读 如何从 NRWL NX 工作区自动部署到 NPM 和 Github 包,以支持使用 GitHub Actions 和语义版本发布进行自动部署。
阅读在开发过程中使用 CLI 库的实用技巧,了解一些有用的开发技巧。
如果您正在使用 GitHub 包管理器,请阅读如何在您的仓库以及 Github Actions 中使用私有 GitHub 包。
参考
https://dev.to/eransakal/create-a-nodejs-command-line-library-with-nrwl-nx-workspace-5hin
使用NRWL-NX-workspace创建一个Node-js-命令行库