由于我自己一直在维护着一个脚手架,也看到了很多脚手架的教程,但是基本都存在一个问题,都是需要执行 -g
这个命令来全局安装再进行使用的。
先不说包的大小如何,我使用这个脚手架,就是单纯用来安装一个项目的,就要我全局安装,是否有些不妥,还有另外一个情况,如果我也安装有另外一个脚手架,两个脚手架的命令重复了呢,那么这种情况下你应该如何解决。
那么接下来我们就来通过一个 demo 来讲解一下我们应该如何避免全局安装才能使用脚手架的情况。
完整代码示例可以看我的仓库代码,如果你感兴趣,你也可以加入进来
shebang 命令
开发脚手架的话,那么必然少不了这个命令 #!/usr/bin/env node
行代码是一个特殊的指令,被称为 shebang
。在 Unix 和类 Unix 系统中,这一指令用于指定脚本的解释程序。
作用是告诉系统使用 env 命令来查找 node 并用其来执行脚本。这是一种跨平台的方法,能确保无论 node 安装在何处,脚本都能被正确执行。
接下来我们来了解一下这条指令的组成部分:
-
#!:这是 shebang 的标记,用于告诉操作系统该行后面的路径是用来执行文件的解释器。
-
/usr/bin/env:这是 env 命令的路径。env 是一个用于运行指定命令的程序,同时将当前环境传递给该命令。使用/usr/bin/env 而不是直接指向解释器(例如/usr/bin/node)的路径,可以使脚本更加灵活,因为它不依赖于解释器的固定安装位置。
-
node:这指示 env 命令查找环境中可用的 node 解释器,并使用它来执行脚本。
当你在脚本文件的第一行添加 #!/usr/bin/env node
,并给予该文件执行权限(例如,通过运行 chmod +x index.js
命令),你就可以直接从命令行运行该脚本,而无需在命令前显式指定 node 命令,例如:
bash
./index.js
最终文件就成功地被我们执行了,而不是像我们往常一样要执行这样的命令:
bash
node index.js
这样做的好处是提高了脚本的可移植性和灵活性,特别是在处理不同环境和系统配置的情况下。
package.json 文件中的 bin 字段
package.json 文件中的 bin 字段是用于指定一个或多个可执行文件的映射。当你的 npm 包安装为全局包时(使用 npm install -g),这些指定的可执行文件会被链接到系统路径中,使得用户可以直接通过命令行调用它们,而不需要指定文件的完整路径。这对于创建 CLI(命令行接口)工具特别有用。
bin 字段可以是一个字符串或一个对象:
-
如果只有一个可执行文件,可以直接将 bin 设置为该文件的路径字符串。
-
如果包含多个可执行文件,bin 则应该是一个对象,键是希望用户在命令行中使用的命令名,值是文件的相对路径。
json
{
"name": "moments",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"bin": {
"moments": "./index.js"
}
}
在之前的代码中,我们在 package.json 文件中添加一个对象,其中 m 的值是 ./index.js
的路径,接下来我们应该模仿全局安装的场景了:
bash
npm link
通过 link 将文件 link 到全局环境下, 这就模拟了我们平常使用 -g
命令来安装脚手架的情况下。
这个时候,我们无聊在终端的哪个位置都能执行 moments 这个命令来执行 index.js
这个文件了。
npx 和 bin 的关系
npx 与 package.json 文件中的 bin 字段有着密切的关联,主要体现在 npx 能够让你轻松地执行 npm 包中定义的可执行文件,无论这些包是全局安装的、局部安装的还是甚至未被安装。
当你在一个项目中局部安装一个 npm
包,并且这个包在其 package.json 的 bin 字段中定义了一个或多个可执行文件,这些可执行文件会被链接到当前项目的 ./node_modules/.bin/
目录下。正常情况下,如果你想要执行这些命令,你需要提供完整的路径(例如,./node_modules/.bin/some-command
)。但是,npx
允许你直接通过命令名执行这些文件,即使它们仅在项目的 node_modules 目录中可用。
这些当我们执行 npx xxx 都是可以运行的,例如当我们执行 npx rollup:
npx 的另一个关键特性是它允许你执行未被全局安装或局部安装的 npm 包中的命令。npx 会在需要时临时安装这些包并执行其中的命令。这种能力部分依赖于 npm 包的 bin 字段,因为 npx 需要知道哪个文件是可执行的。
例如我们要使用大名鼎鼎的 create-neat
这个脚手架(为什么说大名鼎鼎呢,因为是我开发的,我也天天使用,那么它必然是大名鼎鼎啊)它在其 package.json 的 bin 字段中指定了一个可执行文件。通常,你可能会全局安装这个包(npm install -g create-neat)以便使用它提供的命令。但是,npx 允许你直接执行:
bash
npx create-neat moment
在这个例子中,npx 会检查 create-neat
是否在本地安装。如果没有,npx 会临时安装 create-neat
,然后使用它的 bin 指定的可执行文件来创建一个新的 React 应用。这个过程避免了需要全局安装包,同时确保了你总是在使用该工具的最新版本。其实这个最新版的也很重要,因为我们全局安装的可能有些存在的 bug,但是 npm 包上发布了最新版本并且修复了这个 bug,如果你没有关注人家包的最新动态,那么这个 bug 就只有你自己来慢慢摸索了。
因为这个包我在写之前就有用过了,所以也就不需要安装了,我们再换一个,使用 create-next-app 来
当你使用 npx 来执行一个脚手架命令(或任何 npm 包中的命令)时,如果该包没有在你的系统上安装,npx 会临时安装所需的包到一个临时目录中。执行完成后,npx 确实会自动清理并删除这个临时安装的包。这样的设计使得 npx 非常适合执行一次性的命令,如脚手架初始化项目的命令,而不会在用户的系统上留下任何额外的安装包。
当安装完成的时候,就会根据 create-neat 这个 bin 命令来执行可执行命令:
请确保 npm 包名和 bin 的命令相同,这样才能开始执行我们的文件。
总结
npx 提供了一种非常便捷的方式来执行 npm 包中的命令,尤其是对于那些你可能只需要偶尔运行一次的命令,而无需永久安装在你的系统中。
除了 npx 之外,其他包管理工具也可以执行同样的操作。
例如 npm,这个前提需要你的包名是 create-xxx 这样的形式的:
bash
npm init neat my-app
我们也可以使用 pnpm 来执行:
bash
pnpm dlx create-neat my-app
这里,dlx 是 pnpm 提供的一个命令,用于在不永久安装包的情况下执行 npm 包。这与 npx 类似。
我们还可以使用 pnpm create 命令,这为 pnpm 用户提供了一个与 npm init 类似的快速创建新项目的方式。例如:
bash
pnpm create neat my-app
执行脚手架的方法多着呢,这种方法完全不需要我们全局安装,目前我看到的脚手架,似乎只有 nest-cli 适合全局安装的,因为它可以提供给我们快速创建文件。
最后分享两个我的两个开源项目,它们分别是:
这两个项目都会一直维护的,如果你也喜欢,欢迎 star 🥰🥰🥰