发布流程
- 创建一个 npm 项目
bash
mkdir frame-start
cd frame-start
npm init -y
- 创建 bin 文件夹,并在文件夹中创建入口文件
js
#!/usr/bin/env node
console.log('脚手架')
- 在 package.json 中指定入口文件
js
{
"name": "frame-start",
"version": "1.0.0-beta",
"main": "index.js",
"bin":{
"frame-start":"bin/index.js"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": ""
}
- npm 发包
js
npm login
npm publish
使用流程
- 全局安装脚手架
js
npm i frame-start -g
此时可能会有一个报错,如下:
js
npm error code EACCES
npm error syscall symlink
npm error path ../lib/node_modules/frame-start/bin/index.js
npm error dest /usr/local/bin/frame-start
npm error errno -13
npm error [Error: EACCES: permission denied, symlink '../lib/node_modules/frame-start/bin/index.js' -> '/usr/local/bin/frame-start'] {
npm error errno: -13,
npm error code: 'EACCES',
npm error syscall: 'symlink',
npm error path: '../lib/node_modules/frame-start/bin/index.js',
npm error dest: '/usr/local/bin/frame-start'
npm error }
npm error
npm error The operation was rejected by your operating system.
npm error It is likely you do not have the permissions to access this file as the current user
npm error
npm error If you believe this might be a permissions issue, please double-check the
npm error permissions of the file and its containing directories, or try running
npm error the command again as root/Administrator.
npm error A complete log of this run can be found in: /Users/***/.npm/_logs/2025-10-19T08_25_04_472Z-debug-0.log
报错原因:
在执行 npm install -g frame-start
或类似全局安装命令时,npm 试图在 /usr/local/bin/
目录下创建一个符号链接(symlink),但当前用户没有权限写入该目录。/usr/local/bin/
是系统目录,普通用户默认没有写权限,所以会报 EACCES: permission denied
权限错误。
使用 sudo
提升权限执行安装命令
sql
sudo npm install -g frame-start
系统会提示你输入密码,输入后即可完成安装。
- 测试脚手架,执行
frame-start
js
~ % frame-start
脚手架
- 可以查询
frame-start
的安装路径
js
~ % which frame-start
/usr/local/bin/frame-start
~ % ls -l /usr/local/bin/frame-start
lrwxr-xr-x 1 root wheel 44 10 19 16:27 /usr/local/bin/frame-start -> ../lib/node_modules/frame-start/bin/index.js
本地调试脚手架
- 切换到当前开发目录下
js
pwd
/Users/xxx/Desktop/study/frame-start
- 执行
npm link
,这会把当前项目链接到全局 npm 模块:
bash
sudo npm link
原理:利用了 npm 的全局符号链接机制 把本地项目"挂载"到全局 npm 模块和可执行命令目录,实现了本地项目的全局可执行化。
假设项目路径是 /Users/yourname/projects/frame-start
:
在项目根目录执行:
bash
npm link
npm 会做两件事:
- 第一层链接(全局模块目录中的 frame-start):
- 位置:
/usr/local/lib/node_modules/frame-start
- 指向:本地项目根目录
/Users/yourname/projects/frame-start
- 作用:让 npm 把你的本地项目识别为一个 "已安装的全局模块"。这样 npm 可以读取项目的
package.json
(比如其中的bin
配置),为后续创建可执行命令铺路。
- 第二层链接(全局可执行目录中的 frame-start):
- 位置:
/usr/local/bin/frame-start
- 指向:
../lib/node_modules/frame-start/bin/index.js
(即通过第一个链接找到本地项目的入口文件) - 作用:让终端能直接识别
frame-start
命令。因为/usr/local/bin
是系统默认的 "可执行程序搜索目录",终端输入frame-start
时,会自动在这里找到这个符号链接,并执行它指向的bin/index.js
(你的 CLI 入口代码)。
为什么需要两层链接?
- 第一层链接(全局模块目录)的核心是 "让 npm 管理模块元信息"(比如读取
package.json
的bin
配置,知道命令对应的入口文件路径)。 - 第二层链接(全局可执行目录)的核心是 "让系统能识别命令"(把 CLI 入口文件映射到系统可执行路径,实现终端直接调用)。
../lib/node_modules/frame-start 和 /usr/local/lib/node_modules/frame-start 是同一个目录,表示方式不同。
分包脚手架调试
假设你有两个包:
/path/to/frame-start-core
/path/to/frame-start-cli
(依赖 core)
- 先在核心包目录执行:
js
cd /path/to/frame-start-core
npm link
- 然后在 CLI 包目录执行:
bash
cd /path/to/frame-start-cli
npm link frame-start-core
会把 CLI 包中的 frame-start-core
依赖指向你本地的核心包代码,实现本地联调。 3. 在 CLI 包目录执行:
js
npm link
将 CLI 包链接到全局,方便执行命令调试。
- 解除链接
若后续需恢复依赖为 npm 仓库包,可执行:
js
在 CLI 包目录执行 `npm unlink frame-start-core`(解除与本地核心包的关联);
在核心包目录执行 `npm unlink`(从本地全局移除核心包链接)。
脚手架命令注册和参数解析
命令注册
- 执行
frame-start init
- 在入口文件中获取命令
js
const argv = require('process').argv
console.log(argv) // 'init'
参数解析
- 执行
frame-start init --name vue-demo
- 在入口文件中获取参数
js
let [option, param] = argv.slice(3)
option = option.replace('--','')
console.log(option) // name
console.log(param) // vue-demo