Dependency Resolution of npm and pip

30th September 2019 at 10:37am

npm 和 pip 分别是如何解决包依赖冲突的

npm

对于 npm v2,npm install 时每个包都会在各自的 node_modules 文件夹中存放自己的依赖。这样对于一个稍大型的工程,会有成千上万的文件存在。

npm v3 把依赖库尽量地 flatten 到顶级 node_modules 中,但是版本有冲突的情况下,还是使用 v2 的行为。不过这样已经解决很大一部分问题了。(来源

目录结构

对于非 global 方式安装的包,包本身代码和它的依赖是在同一层目录:

$ mkdir test-dir && cd test-dir
$ npm install http-server
$ ls node_modules
async  colors  corser  ecstatic  eventemitter3  he  http-proxy  http-server  mime  minimist  mkdirp  opener  optimist  portfinder  qs  requires-port  union  url-join  wordwrap

对于 global 方式,包的依赖放在它本身的 node_modules 里面,而不是在同一层目录。比如对于 http-server 这个包,它的依赖放在 /usr/lib/node_modules/http-server/node_modules 里面。

无论是哪种方式,npm remove 一个包时都能正确地处理依赖:

  1. 全局方式时,删除该包的最上层目录,如 /usr/lib/node_modules/http-server/node_modules
  2. 非全局方式时,npm 会去读 package.json 文件,判断要删除的包有哪些依赖还被别的包依赖着,这些包不会被删除

pip

pip 并 没有 真正的 dependency resolver ,你可以在 requirements.txt 文件中强制指定依赖库的版本,这会覆盖掉各个库在 setup.py 中指定的版本。

目录结构

pip 安装的包,跟它的依赖最终都会放在同一层目录平躺着。

pip 安装包时是装到一个 env(一般是全局 env / vitualenv),而 npm 装包是针对全局 / 一个项目的。这导致 npm 处理依赖时更为灵活、合理,因为它没有多个项目共享同一套包。所以 pip remove 一个包时,并不会同时删除它的依赖。

Python 的打包感觉太复杂,存在 distutils, setuptools 这两个让我搞不清楚的库,打包格式又有什么 source distribution, egg, wheel 等奇奇怪怪的东西。有必要的时候再研究了。

感觉 npm v3 的解决办法是最好的。