npm-cli-造轮子初体验

我亲手造了一个 npm CLI 命令,然后发现 vite、eslint 全是这么来的

实习第一天,我连「npm 包怎么变成一个命令行命令」都没认真想过。直到今天,我和一个 AI 搭子从零搓了一个 hello 命令------然后突然意识到,我每天在用的那些工具,背后藏的是同一套小秘密。


一、先建一个 npm 项目

bash

bash 复制代码
mkdir hello-cli
cd hello-cli
npm init -y

跑完之后,目录里多了一个 package.json

go 复制代码
hello-cli/
└── package.json

这一步的意义其实就一句话:

告诉 npm:「这里是一个 Node.js 包项目。」


二、在 package.json 里声明一个命令

我们往 package.json 里加了一行关键的东西:

json

json 复制代码
{
  "name": "hello-cli",
  "version": "1.0.0",
  "bin": {
    "hello": "./cli.js"
  }
}

重点就是这段:

json

json 复制代码
"bin": {
  "hello": "./cli.js"
}

它的意思是:

如果用户在终端输入 hello,就去执行 ./cli.js

bin 本质上是一张「命令名 → 文件」的地图 🗺️。


三、写真正干活的代码

然后我们创建了 cli.js

javascript

javascript 复制代码
#!/usr/bin/env node

console.log("🎉 Hello! 我的第一个 npm CLI 包!");

开头这行:

javascript

javascript 复制代码
#!/usr/bin/env node

是告诉系统:

用 Node.js 来运行这个文件。

下面那行 console.log,就是这个命令真正要做的事。


四、把它装到全局

接下来执行:

bash

erlang 复制代码
npm install -g .

这里两个细节:

  • . 表示「当前目录这个包」
  • -g 表示「全局安装」

npm 做了一件很关键的事------它读了 package.json,发现了 bin,然后在系统里注册了 hello 这个命令


五、终于可以直接运行了

以前要这样跑:

bash

复制代码
node cli.js

现在只要:

bash

复制代码
hello

终端立刻输出:

objectivec 复制代码
🎉 Hello! 我的第一个 npm CLI 包!

🎉 你的电脑刚刚「认识」了一个你自己创造的新命令


整个流程串起来

go 复制代码
创建项目
   │
   ↓
package.json
   │
   ↓
定义 bin:hello → cli.js
   │
   ↓
npm install -g .
   │
   ↓
系统注册 hello 命令
   │
   ↓
终端输入 hello
   │
   ↓
Node 执行 cli.js
   │
   ↓
看到输出

我们真正搞懂的,其实就这几样东西:

东西 作用
package.json 描述 npm 包的信息
bin 暴露命令入口(命令名 → 文件)
cli.js 命令实际执行的代码
#!/usr/bin/env node 指定用 Node 执行(主要给 Unix 看)
npm install -g 全局安装命令
CLI Command Line Interface,命令行工具

让我「哦!」一下的三个彩蛋

这个实验做完,我又追问了几个问题,结果挖出三个挺反直觉的点:

1. 在 Windows 上,那行 shebang 其实「没生效」

我写的 #!/usr/bin/env node,是 Unix / Mac 的规矩。Windows 根本不看这行。

那我的 hello 为什么还能跑?因为 npm install -g 在 Windows 上不是建软链接,而是生成了几个包装文件

objectivec 复制代码
hello        ← 给 Git Bash 用
hello.cmd    ← 给 CMD 用
hello.ps1    ← 给 PowerShell 用

真正找到 node 去执行 cli.js 的,是这几个 .cmd / .ps1。shebang 只是「跨平台留个后手」,让同一份代码在 Mac 上也能跑。很多人以为删了 shebang Windows 就坏了------其实没关系。

install -g . 是「复制一份装进全局」。你每改一次 cli.js,都得重装,很烦。

开发阶段应该这样:

bash

bash 复制代码
npm link      # 在包目录里执行一次

它会做一个软链接 指向你的项目。之后你改代码,hello 命令立刻是最新的,不用重装。用完 npm unlink 解绑即可。

3. 命令还分「全局」和「本地」

你装的是全局命令-g)。但真实项目里,90% 的命令其实是本地的,躺在:

bash 复制代码
node_modules/.bin/

比如你 npm install 之后,vite 其实装在 node_modules/.bin/vite,并没进全局。你能在 package.jsonscripts 里直接写 "dev": "vite",是因为 npm 跑 script 时会自动把 node_modules/.bin 加进 PATH


结尾:你刚打开的是一扇门

最有意思的一点是------你刚刚做的事,和很多大型工具本质一样:

markdown 复制代码
你的 hello
      ↓
npm 包
      ↓
bin
      ↓
终端命令

和:

markdown 复制代码
vite
      ↓
npm 包
      ↓
bin
      ↓
vite 命令

同一套机制

只是 Vite 里面不是打印一句 Hello,而是启动开发服务器、构建项目 😂

所以你刚刚其实不是「玩了个小例子」,而是亲手拆开了 npm 生态的一扇门 🚪✨ 以后看到 viteeslinttsc 这些命令,你会知道它们背后都藏着一个类似的 bin 小秘密。

一句话钉进脑子:

bin 定义命令、scripts 编排命令、.bin 存放本地命令、npm link 用于开发、shebang 是给 Unix 看的。


本文所有示例均为脱敏后的通用技术演示,不涉及任何公司项目细节。

相关推荐
不在逃避q17 小时前
Trae/Vs Code/Cursor命令行无法跑npm命令
前端·arcgis·npm
半句唐诗1 天前
我是如何通过 Access Token 成功发布第一个 npm 包的
前端·npm·node.js
NutShell Wang2 天前
零依赖架构实战:451个HTML文件如何用63KB平均体积交付3584个交互模块
前端·人工智能·arcgis·npm·开源·html·vibe coding
兮动人5 天前
Linux 安装 Claude Code 实战:Node.js、npm、GLM 配置一次跑通
linux·npm·node.js·cc·claude code
lastHertz14 天前
openskill 实战指南:像管理 npm 包一样管理你的 AI Skill
前端·人工智能·npm
qq_5896660515 天前
npm install npm install -g @vue/cli 分别是什么意思以及安装路径
前端·vue.js·npm
Dreamboat-L16 天前
NVM的安装与使用(保姆级教程)
npm·node.js
无责任此方_修行中17 天前
踩坑实录:为什么 `pnpm run` 会偷偷帮你装依赖?—— 浅析 pnpm 与 npm run 的底层差异
javascript·后端·npm
ShiXZ21319 天前
指令集-NPM 常用指令速查手册
前端·npm·node.js