blog icon indicating copy to clipboard operation
blog copied to clipboard

你所不知道的模块调试技巧 - npm link

Open atian25 opened this issue 8 years ago • 62 comments

1. 背景

node 应用开发中,我们不可避免的需要使用或拆分为 npm 模块,经常遇到的一个问题是:

新开发或修改的 npm 模块,如何在项目中试验?

新同学一般会有以下几种方式:

为了方便示范,我们假设项目是 my-project, 需要用到一个独立的 my-utils 模块

1.1 发布一个 beta 版本

  • 优点:你高兴就好。
  • 缺点: 无趣+无趣+无趣,麻烦+麻烦+麻烦。

1.2 直接用相对路径安装

$ cd path/to/my-project
$ npm install path/to/my-utils
  • 优点:简单明了
  • 缺点: 调试过程中往往需要微调,此时需要切换到 my-utils 目录修改,然后反复重新 install,很麻烦

1.3 使用软链

$ cd path/to/my-project/node_modules
$ ln -s path/to/my-utils my-utils
  • 优点:软链后,两边修改直接同步
  • 缺点: 指令操作麻烦,不同操作系统语法不一样

2. 正解 - npm link

但其实 npm 本身已经对此类情况提供了专门的 npm link 指令。

相关文档: https://docs.npmjs.com/cli/link

下面我们简单介绍下用法:

$ cd path/to/my-project
$ npm link path/to/my-utils

简单的替换一个单词,就搞定了,cool~

如果这两种的目录不在一起,那还有一种方法:

$ # 先去到模块目录,把它 link 到全局
$ cd path/to/my-utils
$ npm link
$
$ # 再去项目目录通过包名来 link
$ cd path/to/my-project
$ npm link my-utils

该指令还可以用来调试 node cli 模块,譬如需要本地调试我们的 egg-init,可以这样:

$ cd path/to/egg-init
$ npm link
$ # 此时全局的 egg-init 指令就已经指向你的本地开发目录了
$ egg-init # 即可

想去掉 link 也很简单:

$ npm unlink my-utils

3. 写在最后

  • 该方法只是为了最后一步调试,模块本身的正确性,应该更多的通过单元测试来保证。
  • 单元测试相关内容,可以参见:单元测试

atian25 avatar Jan 24 '17 07:01 atian25

👍,当年修改 node_modules 后发布了一次导致 node_modules 里面的代码直接没了给我留下了 深刻 的记忆 😂

rccoder avatar Feb 09 '17 13:02 rccoder

问题是一个项目里面被 flatten 出来几千个目录,你就算开个软连,编辑器里面展开 node_modules 目录也会被卡死。

XadillaX avatar Feb 28 '17 09:02 XadillaX

@XadillaX 这个跟 link 关系不大,是 npm@2,npm@3,cnpm 的包安装方式区别导致的吧。

这是编辑器的问题,很容易解决的,vscode 和 webstorm 配置几个 ignore 就 ok 了。(局部 ignore,不用全部屏蔽整个 node_modules)

atian25 avatar Feb 28 '17 09:02 atian25

@atian25 为什么大家都喜欢把 NPM 自身机制问题总要归结到编辑器问题上去呢 -。 -

XadillaX avatar Feb 28 '17 10:02 XadillaX

因为 NPM 我们改变不了,只好改编辑器了 (摊手)

发自我的 iPhone

在 2017年2月28日,18:44,Flandre Scarlet [email protected] 写道:

@atian25 为什么大家都喜欢把 NPM 自身机制问题总要归结到编辑器问题上去呢 -。 -

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

atian25 avatar Feb 28 '17 10:02 atian25

呀, 感觉如果是用yarn install的话用yarn link会好一点的呢。具体原因不太清楚, 在yarn下载然后用npm(npm5) link感觉npm会去处理环境生成一个lock文件, 处理起来有点慢的呢, 用yarn就一秒左右就搞定了。不过确实link的方式在开发的时候确实是不错的思路。感谢分享。

monkindey avatar Jul 13 '17 07:07 monkindey

那,如果我的js插件直接放到项目目录下呢

lightWey avatar Aug 16 '17 03:08 lightWey

@lightWey 然后你的问题是?

atian25 avatar Aug 16 '17 03:08 atian25

🤔 我居然每次都 npm install path/to/my-project --save 一次,没有想到用 link...

ahonn avatar Aug 16 '17 07:08 ahonn

有一个模块,开始是直接通过npm install gitlab地址,运行项目没错,但是在本地,我通过npm link之后,运行就出错了,

sunlandong avatar Nov 27 '17 05:11 sunlandong

@sunlandong 这种反馈对交流是没有任何帮助的,出什么错?错误信息是啥?复现步骤是啥?挤牙膏似的交流是最没效率的。

atian25 avatar Nov 27 '17 05:11 atian25

你好,我目前也是需要把一些基础的vue组件分离出去单独做一个npm的包,试了npm link这个办法,理论上是没有问题的,可以达到想要的目的。但是我遇到的问题可能和vuejs/babel更相关一些,由于vue组件在分离前,有webpack配置好了babel去解析,但是在分离出去之后,似乎要给新的npm模块单独做一个构建的流程?我现在只是单纯的把一些vue文件抽离了,放到另一个git仓库了,然后用一个入口文件import/export 所有的组件,然后问题是启动webpack server的时候会无限卡在等待打包的过程。我感觉就是缺了对分离出去的npm模块的解析过程。

请问有没有类似vue/react组件本地开发流程的经验分享?谢谢啦

renyuanz avatar Dec 11 '17 13:12 renyuanz

应该没区别的,npm link 只是对目录做了一个软链而已,文件系统层面的,工具层面的应该是无感知的,除非工具那边不支持跟随软链(应该不会)。

npm link 只是在需要本地测试的时候用到的。

atian25 avatar Dec 11 '17 14:12 atian25

是否每次install的时候都需要设置下软链,软链会不会被记录在lock.json文件中,如果能记录是不是说明能够解决特定的npm package放到自己的项目中维护

AsceticBoy avatar Feb 07 '18 03:02 AsceticBoy

link 只是用于调试用的。

atian25 avatar Feb 07 '18 03:02 atian25

好吧,我本来以为能解决自己维护 package 的问题

AsceticBoy avatar Feb 07 '18 03:02 AsceticBoy

既然提到了ln,那还是直接ln -s吧?跟ln有什么区别?

qwIvan avatar Apr 07 '18 08:04 qwIvan

@qwIvan

  1. npm link 后,该项目会被 link 到全局去,你就能测试命令行了
  2. 在上面那句后,可以直接 npm link pkgName 来在应用中 link,不需要 ln 复杂的相对路径。
  3. ln 不同操作系统的语法不同

atian25 avatar Apr 08 '18 00:04 atian25

大神你好,我这里遇到一个问题,npm install 之后,在node_modules/.bin/ 里面没有创建软连接,都是硬链。(node V8.4.0 npm V5.3.0)这个情况是在 生成环境打包时候发现的,本地和测试环境都没问题,我还尝试过,把生成打的包下载之后,删除node_modules 和 package-lock.json文件,然后本地npm install,这样生成.bin文件夹里会自动创建软链。所以 请问一下大神,有没有碰到过这样的情况,npm 在什么情况下不会自动创建软链的?

llsldwy avatar Apr 17 '18 07:04 llsldwy

没遇过。

atian25 avatar Apr 17 '18 07:04 atian25

@llsldwy 你那个问题很大可能是你打包的问题, tar 或 zip 的时候多了一个参数

atian25 avatar Jun 26 '18 08:06 atian25

你好 ,有个问题,我在npmlink后,不能彼此共享node_modules,执行脚本的时候找不到安装依赖

sunha1yang avatar Jun 27 '18 08:06 sunha1yang

@sunha1yang 啥叫共享 node_modules?

atian25 avatar Jun 27 '18 08:06 atian25

sorry, 我表述上有点问题,我要测试pkg有一些依赖,如webpack等第三方包,我在另一个文件夹(此文件夹下有node_modules文件,pkgName需要的依赖包都存在)下npm link pkgName后,我的pkg引不到此文件下node_modules文件,然后就会报错,我的问题是如何能让我的pkg能够引到当前文件夹下的node_modules文件?

不知道我有没有表述清楚......

sunha1yang avatar Jun 27 '18 08:06 sunha1yang

还是没懂,搞个 tree 图呗

atian25 avatar Jun 27 '18 08:06 atian25

question

这个是我的操作步骤

sunha1yang avatar Jun 27 '18 09:06 sunha1yang

我指的是这样描述下。。。

.
├── app
├── config
├── node_modules
│   └── aaa -> link to ./app/xx/xx
└── package.json

atian25 avatar Jun 27 '18 09:06 atian25

目录结构是这样的:

.
├── fe
├── awt ->npm link
├── project -> 在项目目录下 npm link awt
│   ├── app
│   ├── node_modules
│   └── package.json
|   └── config
└── otherproject
    └── home.html

sunha1yang avatar Jun 27 '18 10:06 sunha1yang

很有用,基本你上面提到的第一种方法,以及后面的都用过 哈哈

azl397985856 avatar Jun 29 '18 02:06 azl397985856

问一下,typescript的项目,怎么解决这个问题

qwIvan avatar Sep 15 '18 19:09 qwIvan

没啥区别吧

atian25 avatar Sep 16 '18 12:09 atian25

楼主你好。我现在遇到一个问题 我现在有一个模块lib文件夹(lib中package.json库名称是"@sml/lib")跟project项目文件夹 我切换到lib下执行npm link 然后再切换到project文件夹下执行 npm link @sml/lib 在项目中引入lib后刷新就报错了。 Unable to resolve module @sml/lib from /Users/sml2/Documents/iOSDemos/RNBaseProject/App.js: Module @sml/lib does not exist in the Haste module map 这是为什么呢

qq912276337 avatar Oct 09 '18 10:10 qq912276337

@sunha1yang npm link 会遇到依赖找不到的问题,不是好用(没有问题的话还是尽量使用 npm link)

https://medium.com/@vcarl/problems-with-npm-link-and-an-alternative-4dbdd3e66811

zhbhun avatar Dec 19 '18 06:12 zhbhun

依赖找不到的问题,可以用https://nodejs.org/api/cli.html#cli_preserve_symlinks 这个解决的,朋友们

brizer avatar Apr 24 '19 09:04 brizer

@brizer 请问这个--preserve-symlinks 是node命令,怎么使用?

VictorWu90 avatar Sep 17 '19 07:09 VictorWu90

@brizer 请问这个--preserve-symlinks 是node命令,怎么使用?

举个例子,你用vscode调试的时候,a依赖了b,而b是npm link的,那么在a项目的调试配置中加一句:

"runtimeArgs":[
    "--preserve-symlinks"
]

就可以修改b,顺便调试a了。

brizer avatar Sep 17 '19 08:09 brizer

@brizer 我这是一个webpack构建的web项目,比如a依赖b, a和b都依赖vue这个框架,我通过构建a跑在webpack-dev-server上,用chrome打开调试,这个我该如何操作呢

VictorWu90 avatar Sep 17 '19 08:09 VictorWu90

@brizer 我这是一个webpack构建的web项目,比如a依赖b, a和b都依赖vue这个框架,我通过构建a跑在webpack-dev-server上,用chrome打开调试,这个我该如何操作呢

微信 brizer1992 单独聊,没太明白你问题是什么。

brizer avatar Sep 17 '19 09:09 brizer

@brizer 我在此处找到了问题的解决,万分感谢提供解答与搜索思路。

VictorWu90 avatar Sep 17 '19 09:09 VictorWu90

@VictorWu90 优秀

brizer avatar Sep 17 '19 09:09 brizer

在webpack构建的项目中,可以使用resolve-alias字段使用绝对路径强制指定调试时第三框框架的源目录,

resolve: {
        extensions: ['.js', '.vue', '.json'],
        alias: {
            'vue-router': resolve('node_modules/vue-router'),
            vuex: resolve('node_modules/vuex'),
            'vue$': resolve('node_modules/vue/dist/vue.esm.js'),
            // 'vue$': 'vue/dist/vue.esm.js',
            '@': resolve('src')
        }
    }

VictorWu90 avatar Sep 28 '19 04:09 VictorWu90

请教一下,如果我的一个项目依赖了A组件,A模块又依赖了B组件,那么我如果要在项目中调试B组件,应该怎么快速的link?

orangeyyy avatar Oct 09 '19 13:10 orangeyyy

cd a/node_modules && npm link c

atian25 avatar Oct 09 '19 15:10 atian25

这里有另一种方式,我们在项目里经常用到,就是直接通过 npm 的 package.json 中的依赖版本来指定。比如我当前开发的项目依赖一个组件库 element-react-dataview,那么我会将此组件库的代码 clone 到 lib/element-react-dataview,然后将 package.json 中的引用改成:

{
  "dependencies": {
    "element-react-dataview": "file:lib/element-react-dataview"
  }
}

项目目录下运行 npm i 之后再删除掉 lib/element-react-dataview/package.json(因为 npm 发布版引用的是编译后的 dist 文件,没有此情况的可以不用删除),启动项目的 webpack-dev-server 之后引用的就是对应库的源码了,可以随时修改并进行调试。

这其实也是另一种形式的 npm link

mytharcher avatar Oct 10 '19 05:10 mytharcher

lerna

foxundermoon avatar Feb 17 '20 00:02 foxundermoon

学到了,thx

fireairforce avatar Mar 05 '20 16:03 fireairforce

对npm install指令和npm link指令更加理解了。

coconilu avatar Mar 08 '20 09:03 coconilu

1.通过npm link给公共组件建立软链接 2.在项目中通过npm link 包名引入后,Module not found: Error: Can't resolve 'vue-loader/node_modules/vue-hot-reload-api出现这个报错是什么情况,有朋友解答下么,这个依赖在vuecli创建的时候就已经有了啊

Mr-xue avatar Apr 20 '20 08:04 Mr-xue

可能是 vuecli 对软链的处理不好。

atian25 avatar Apr 20 '20 09:04 atian25

可能是 vuecli 对软链的处理不好。

找到问题了,需要把webpack配置中的 symlinks设为false,否则就会报错,为了解决这个问题头都秃了。。。

Mr-xue avatar Apr 21 '20 06:04 Mr-xue

可能是 vuecli 对软链的处理不好。

找到问题了,需要把webpack配置中的 symlinks设为false,否则就会报错,为了解决这个问题头都秃了。。。

是的,很好

brizer avatar Apr 21 '20 07:04 brizer

wml这个才是最屌的,因为React Native 不支持 npm link,https://www.bram.us/2018/03/10/working-with-symlinked-packages-in-react-native/

youngjuning avatar Jul 08 '20 10:07 youngjuning

Metro 不支持跟随软链: https://github.com/facebook/metro/issues/1

youngjuning avatar Jul 10 '20 08:07 youngjuning

npm link贼好用

littlepoolshark avatar Sep 28 '20 06:09 littlepoolshark

可能是 vuecli 对软链的处理不好。

找到问题了,需要把webpack配置中的 symlinks设为false,否则就会报错,为了解决这个问题头都秃了。。。

💥就是这个害我浪费了半天时间

tian0o0 avatar Sep 28 '20 08:09 tian0o0

我发现 1.2 相对路径安装 修改代码后不需要重新 install 呀

afishhhhh avatar Oct 19 '20 18:10 afishhhhh

在引用的项目中使用安装插件导致被引用的插件废掉,被引用的模块需要清理掉node_modules重新安装才能成功启动

LS-LILEI avatar Jun 06 '21 06:06 LS-LILEI