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 看的。


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

相关推荐
阿萨德528号19 小时前
npm 包发布实战指南:从零发布、更新迭代到版本治理
前端·npm·策略模式
赖龙2 天前
pnpm vs npm
前端·npm·node.js
dyxal3 天前
ENOSPC 错误完全解析:文件监视器数量不足的终极解决方案
npm
_codemonster4 天前
npm run dev 是在开发模式运行,怎么在生产环境运行
前端·npm·node.js
暂时先用这个名字7 天前
安装deepseek harness及插件
人工智能·ai·npm·pnpm·deepseek·深度求索·harness
Lyra_Infra8 天前
OpenClaw 升级及 Channel 安装故障排查与遗留问题分析
后端·npm
紫禁玄科10 天前
Shai-Hulud:npm生态的自我复制蠕虫风暴
前端·npm·node.js
fastjson_13 天前
Hadoop之Yarn
大数据·hadoop·npm
晓得迷路了13 天前
栗子前端技术周刊第 141 期 - Next.js 16.3、npm 安全事件、2026 CSS 现状调查报告结果...
前端·javascript·npm
周小董13 天前
[1367]npm 安装 canvas 报错 node-gyp ERR
前端·npm·node.js