简单易用
从最初接触 npm / yarn 这两个 Node.js 的包管理器到现在已经一年多了,最大的感受就是:简单易用。
相比 Python 的包管理器 pip 和 Java 的包管理器 Maven, npm / yarn 简直好用太多了。仔细想想也很合理,Node.js 比 Python 和 Java 晚诞生了那么久,自然有机会配备更成熟的包管理器。
不过也正因为其简单易用,很少碰到问题,所以我对 npm / yarn 从来没有认真了解过。直到最近参与了一个项目,依赖关系比较复杂,有时竟然需要手动修改 yarn,lock
,这才不得不找时间看了看 npm / yarn。
这篇文章简单谈谈我对 npm / yarn 的印象。首先对比一下 Java 和 Python 的包管理器。
对比 Java 的包管理器:Maven
相比 npm / yarn,Maven 有两个很大的缺陷:
- Maven 只有一个全局的本地仓库,会把你电脑里所有使用 Maven 管理的 Java 项目的依赖全部下载到这个目录下(一般叫做
.m2
,连名字也很奇怪,不如node_modules
简单直接!)
这显然是非常不方便的。一方面,你很难直观地看到每个项目的依赖有多少;另一方面,如果某个项目的依赖出了问题,想要把项目依赖全部删除重新下载也很难办到,因为所有项目的依赖都是混在一起的。无奈只好把整个 .m2
文件夹删除。
在这一点上,npm / yarn 设计得非常合理,项目依赖默认安装到项目根目录的 node_moduls
下,不仅方便浏览,而且出问题了直接把这个文件夹删了重装也很方便。
第二个缺陷更为致命:
- Maven 无法处理“依赖地狱”的问题。简单来说,如果你的项目有两个依赖 A 和 B,它们又分别依赖不同版本的 C,例如
C@1.0.0
和C@2.0.0
,那么 Maven 并不能在适当的位置分别使用C@1.0.0
和C@2.0.0
,而是只能让你选择 C 的一个版本在程序运行时加载。
Maven 这是多么脑残的设计!!万一你需要的两个 C 的版本不兼容呢?那就真是欲哭无泪了。(当然了,Java 还有另一个流行的包管理器 Gradle,不过我还没用过)
相比之下,npm / yarn 依然没有让人失望。假如你先安装了 A,由于 A 依赖 C@1.0.0
,那么项目默认的 C 的版本就会是 1.0.0
;当你安装 B 的时候,B 所需要的 C@2.0.0
就会安装到 B 自身目录下的 nodee_modules
下面,类似于这样:
node_modules
A@x.x.x
B@x.x.x
node_modules
C@2.0.0
C@1.0.0
问题完美解决!
对比 Python 的包管理器 pip
不得不说,Python 的包管理体系在我看来十分混乱。直到如今,我都没完全搞清楚在 Python 中如何正确使用 relative import 。
如果你只用 Python 默认的 pip 包管理器下载,那么会遇到一个很麻烦的问题:
- pip 会把你需要的软件包下载到某个全局目录下,和其他的项目共用同一个版本。如果你首先用 pip 安装了依赖 A 的某个版本,例如
A@1.0.0
,那么当你在另一个项目中用 pip 安装A@2.0.0
的时候,A@1.0.0
就会被覆盖。
pip 这又是一个多么脑残的设计!!让我们再次感受一下 npm / yarn 的优秀和伟大。做一个 JavaScript 开发真是一件幸福的事情!
当然了,Python 中不是没有解决的办法:你可以使用 virtualenv 这个工具,为每个项目安装一套相互隔离的依赖,储存在项目目录下的 .venv
文件夹下,类似于 node_modules
。好吧,但为什么要这么麻烦??这个功能不应该默认支持吗,竟然还需要使用第三方工具,真是无语。。
并且,即便你使用了 virtualenv 这样的“隔离”工具,还是有一点需要吐槽:
- 如果你想看一下项目的依赖列表,叫做
requirements.txt
(相当于 Node.js 中的package-lock.json
或者yarn.lock
),那么你在项目目录中是找不到这个列表的,需要你手动运行命令来生成!每次我都要上网搜一下那个生成命令。
当然了,Python 还有另一个流行的包管理器:conda,解决了 pip 的很多问题。不过这又让 Python 的包管理体系更加混乱了。。
小结
本来想主要写一写 npm / yarn 的特性和有意思的地方的,结果发现光是做对比就占了这么大篇幅。
不过也是,只有在对比中才能更加凸显 npm / yarn 的特性和优点。能够使用 npm / yarn 这样优秀的包管理器真是一件幸福的事情。
之后的文章再写写 npm / yarn 其他有意思的地方吧!