再见二丁目 | yitimo的个人日志

再见二丁目

使用npm-link命令帮助开发npm包

修改于: 2023-08-27 16:32

npm link 命令核心原理即使用 symlink 能力建立本地npm包目录的软链接, 本文将基于官网v8.x文档归纳其一些特性和用法.

本文内容基于 node@v16.x, npm@v8.x

在本地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的情况下像这样:

global_npm_pkgs

npm ls -g也能看到link到全局的包

如果link的包名是基于某个命名空间的, 比如 @hello/world, 那列出的就是目录 @hello, 再进去就是 world 目录咯.

如果link到全局的包还包含了bin配置, 像这样:

pkg with bin

则也能被link到全局bin下:

pkg bin in global

在本地另一工程下(以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安装的包一样来使用:

pkg utils in pkg host

npm link比较适合的用途之一就是帮助开发npm包项目, 可以不实际发布包版本就做到”真包调试”, 但也有一些区别和要注意的点:

会link整个目录: 常规安装npm包时, 实际上安装到node_modules内的是npm pack的产物, 会应用.npmignore规则只安装真正被发布的子文件或目录, 而npm link终究只是个symlink, 实际上会link整个目录, 包括所有子文件和目录.

妥善取消link: 当认为开发完成, 并想要取消link时, 可以这么做:

以上两步只是从pkg-host工程里移除了link过来的pkg-utils, 实际上pkg-utils还被link在全局呢, 想要移除全局的link, 可以使用npm uninstall/rm -g命令, 就像正常移除一个全局安装的包一样:

rm pkg_utils from global

使用ts开发的工程, link后使用的应该(should)是编译后的js模块, 而不是原始的ts模块, 按照一般的tsconfig配置, 会忽略node_modules内的ts模块, 而使用编译后的commonjs模块, 这就需要npm包工程在link后, 继续改动ts模块时, 还要记得重新进行tsc编译, 生成最新的js模块供宿主工程使用.

或者也可以专门配置宿主工程的tsconfig, 来包含node_modules中这个npm包的ts模块, 但更建议的方式是写一个脚本监听相关文件改动, 然后自动编译ts到js.

还要注意哪些?

拓展阅读

什么是synlink? 一图流解释:

symlink

什么是bundleDependencies?

yarn和pnpm 都有自己的link实现方式, 要避免混用