使用npm-link命令帮助开发npm包
修改于: 2023-08-27 16:32
npm link 命令核心原理即使用 symlink 能力建立本地npm包目录的软链接, 本文将基于官网v8.x文档归纳其一些特性和用法.
本文内容基于 node@v16.x, npm@v8.x
npm link 做了什么
在本地npm包仓库下运行命令 npm link
后, 应该会看到这样的输出:
added 1 package in 495ms
或者这样的:
up to date in 744ms
内部其实是 建立了当前npm包目录到npm全局的symlink, 也就是 ln -s
命令做的事情.
那么npm全局目录在哪呢, 可以运行命令 ls -l $(npm root -g)
, 如果刚才npm link
成功了, 应该能看到link的包被列出, 以及你此前全局安装过的其他npm包也在这里.
比如使用了nvm
的情况下像这样:
npm ls -g
也能看到link到全局的包
如果link的包名是基于某个命名空间的, 比如 @hello/world
, 那列出的就是目录 @hello
, 再进去就是 world
目录咯.
如果link
到全局的包还包含了bin
配置, 像这样:
则也能被link
到全局bin
下:
npm link pkg-utils 做了什么
在本地另一工程下(以pkg-host
为例)执行 npm link pkg-utils
, 会看到类似 changed [n] packages in [m]s
的输出, 就好像在host
工程内安装了pkg-utils
这个npm
包一样.
但本地link
默认不会改变package.json
文件内容, 即如果package.json
里之前有该包且版本号为^1.0.0
, link本地包时并不会被修改为 file://../path/to/pkg-utils
.
如果link了原本未安装的新包, 则
package-lock.json
会被改变, 如果原来已经安装了, 则也不会改变
最终效果也就是pkg-utils
包所在的本地目录被软链到了pkg-host
工程的 node_modules
中, 然后可以像使用常规npm i
安装的包一样来使用:
使用 npm link 进行 “真包调试”
npm link
比较适合的用途之一就是帮助开发npm包项目, 可以不实际发布包版本就做到”真包调试”, 但也有一些区别和要注意的点:
会link整个目录: 常规安装npm包时, 实际上安装到node_modules内的是npm pack
的产物, 会应用.npmignore
规则只安装真正被发布的子文件或目录, 而npm link
终究只是个symlink
, 实际上会link整个目录, 包括所有子文件和目录.
妥善取消link: 当认为开发完成, 并想要取消link时, 可以这么做:
- 在
pkg-host
里重新运行npm i
或npm i pkg-utils
, 也就是重新装一次这个npm包, 这样做会把link的包挤掉, 安装回package.json
内声明好的版本 - (不推荐) 在
pkg-host
里npm unlink pkg-utils
, 实测这同时会移除 package.json 里的包依赖(如果此前安装了)
以上两步只是从pkg-host
工程里移除了link过来的pkg-utils
, 实际上pkg-utils
还被link在全局呢, 想要移除全局的link, 可以使用npm uninstall/rm -g
命令, 就像正常移除一个全局安装的包一样:
使用ts开发的工程, link后使用的应该(should)是编译后的js模块, 而不是原始的ts模块, 按照一般的tsconfig配置, 会忽略node_modules内的ts模块, 而使用编译后的commonjs模块, 这就需要npm包工程在link后, 继续改动ts模块时, 还要记得重新进行tsc编译, 生成最新的js模块供宿主工程使用.
或者也可以专门配置宿主工程的tsconfig, 来包含node_modules中这个npm包的ts模块, 但更建议的方式是写一个脚本监听相关文件改动, 然后自动编译ts到js.
还要注意哪些?
- npm link 支持多个包: 在包1和包2各自
npm link
后, 在包3里npm link 包1 包2
即可同时 link 两个包 - 工程化项目如何判断某个包是link状态:
fs.lstatSync('包所在的node_modules下的目录').isSymbolicLink()
- link 某个包后 publish: 这样做是可以的, 但需要把link的包列在
bundleDependencies
里, 如果此前没安装这个包, 还需要执行npm install <dep> --package-lock-only
, 然后在pkg-host里运行npm publish
会将目前link的pkg-utils
内容一起打包进npm pack
产物里. 但个人不建议这么做, link应该只用在本地调试 - …
拓展阅读
什么是synlink? 一图流解释:
yarn和pnpm 都有自己的link实现方式, 要避免混用