为什么 npm 要为每个项目单独安装一遍 node_modules?

3,493 阅读7分钟
转载:https://www.cnblogs.com/weiyinfu/p/8471407.html

其实也不用每次都安装node_modules,直接使用软连接即可:
windows 使用mklink /j node_modules %APPDATA%\Roaming\npm\node_modules
linux使用ls -s node_modules %APPDATA%\Roaming\npm\node_modules

nodejs中package.json中的依赖必须每个项目都有自己的node_modules文件夹,而无法在多个项目之间共用一套node_modules(像Java中的Maven那样)。

依赖管理是每个现代语言的标配。依赖管理和打包工具是两个概念,npm是依赖管理,webpack是打包工具。
在Java中,maven既能实现依赖管理又能实现打包。

何为依赖管理?
依赖管理说白了就是构建一个有向无环图。项目A依赖项目B,项目B依赖项目C,那么当你的项目依赖A的时候,依赖管理工具会自动让你的项目依赖B和C。
要想构建有向无环图,最关键的是要将项目转化为有向无环图中的结点。所以对于项目往往有description,作者信息,版本信息等额外信息。
依赖管理最难解决的问题就是版本问题。库A依赖库B,库C也依赖库B,但是库A跟库C所依赖的库B不是同一版本,如果库B的这两个版本兼容还好,如果不兼容就坑大发了,这是无解的问题。

下面说说Java,Python,Node三种语言中的依赖管理。

  • Java中的Maven仓库在开发者电脑上是全局的,所有项目的依赖都集中存放在本地仓库中。每个项目都有pom.xml指明依赖本地仓库中的哪些库。
  • Python中的pip跟maven很像,在开发者电脑上也是集中存放包,但是它不存在版本问题。也就是说,在你的电脑上每个python库都只有一个版本。既然如此,当你依赖某个库的时候,就无需指明版本号,直接引用包的名称就可以了。
  • Node中的依赖如果你不写package.json,那么依赖的就是全局的库;如果写了package.json,就会把所有依赖下载到node_modules文件夹。

Node这种node_modules文件夹的方式有利有弊。
最明显的坏处是:

  • 每次都需要安装依赖,费流量,网速慢时很费时间
  • 浪费磁盘空间,每个node_modules中包含的工具很多,动辄20M

最明显的好处是:

  • 使用package.json安装好之后,node_modules文件夹中没有版本信息,从而package.json可以删掉了。
    移动/复制/打包项目比较简单,对于开发、部署都有好处
  • 对于设计npm的人来说,这是最省事的包依赖方法。这就好比maven安装依赖之后自动将jar包安装到项目的lib里面。
  • 随意改代码。安装在node_modules里面的东西,你可以随便改,无需担心对其它项目的影响。在Java中使用maven管理项目时,如果想要定制某个库,就需要更改这个库的源代码,这时就需要把这个库的源代码复制到项目中,跟node_modules是一个道理。npm的设计者大概认为:前端都是经常修改库的源代码的。

我认为不同语言对于依赖的定位不同。Java中的库是严谨的库,Python中的库是玩具一样、随手写就的库,Node里的库是代码片段一样的库。Node里面的库既然定位就是代码片段,那么当然要将代码片段跟你的项目放在一起了,这样才方便你修改这些代码片段。可是随着时间推移,node中的库越来越大、越来越严谨,这种对待代码片段的方式就有些不好了。

总结:这是一种设计,这种设计有利有弊。

以下是知乎上的回答片段:

全局依赖的唯一好处就是省了硬盘空间。这种省毫无意义。首先如果你要为几十几百兆的硬盘空间斤斤计较,那么也许你已经穷得不适合做开发。其次如果需要支持全局多版本也省不了多少。至于有人说的,每次npm install时间太长,我认为这也不是个事。npm install又不是天天搞,而且只是第一次全新checkout的时候比较慢,以后都是增量更新。实在嫌慢(比如因为防火墙的原因),可以把node_modules一起提交到git里去。
其实我觉得完全可以做成全局的,依赖模块都装到公共目录,每个项目在 npm install 时用符号连接把每个模块对应的版本目录连过来,或者干脆就在 require() 时去全局的模块目录里去找,这样也不麻烦。实际上我团队就包了这样一个命令,安装时是全局安装,项目 init 时符号连接过来,很省时间和空间。但 npm 没有这么做,我觉得一是在一开始没考虑到,后面也就不好改了。实际上就连 node_modules 模块多层嵌套导致路径过长的问题,也是一开始设计时没考虑周全,到了 npm3 才改。

Java在20年前就解决这个问题了,然后后面抄的语言没有一个完全抄对的


npm安装出现警告,如何解决?


E:\node\promise>npm install bluebird
E:\node
`-- bluebird@3.5.0

npm WARN enoent ENOENT: no such file or directory, open 'E:\node\package.json'
npm WARN node No description
npm WARN node No repository field.
npm WARN node No README data
npm WARN node No license field.

E:\node\promise>

为什么每次我npm安装库都会提示找不到 package.json? 我在node目录下也确实找不到package.json.如何解决,求解。


因为你需要先npm init,进行创建package.json
package.json是对于这个项目的基本信息和描述,作者,仓库地址,依赖项目,以及部分npm命令相关等等。


npm中package-lock.json的作用:npm install安装时使用

简单理解: XYZ 的格式

对应为: 主版本号.次版本号.修订号,版本号递增规则如下:

主版本号:当你做了不兼容的 API 修改,

次版本号:当你做了向下兼容的功能性新增,

修订号:当你做了向下兼容的问题修正。

  假设我们创建了一个新项目,它将使用express。 在运行npm init之后,在撰写本项目时,最新的express版本是4.15.4。 (默认情况下,npm 将安装最新版本)

因此在package.json中,"express":"^ 4.15.4"被添加作为依赖项。 假设明天,express的维护者会发布一个 bug 修复,所以最新版本变成了4.15.5。 然后,如果有人想要为我的项目做贡献,他们会克隆它,然后运行 npm install, 因为4.15.5是一个更高版本的主要版本,这是为他们安装的。 我们都有express依赖,但我们有两个不同的版本。 理论上,它们应该还是兼容的,但是也许这个 bug 会影响我们正在使用的功能,而我们的应用程序在使用Express版本4.15.4与4.15.5进行比较时会产生不同的结果.

  而package-lock.json的作用就是用来保证我们的应用程序依赖之间的关系是一致的, 兼容的.

  当不存在package-lock.json文件时,使用npm install时,会自动生成这个文件。当存在这个文件时,使用npm install安装,会安装package-lock.json里指定版本的插件,而且相比没有package-lock.json文件时,安装速度会快很多。因为package-lock.json文件里已经存在插件的版本、下载地址、整个node_modules的结构等信息。

  当存在package-lock.json文件时,每次npm install安装就会安装package-lock.json里对应插件的版本。这样同一份package-lock.json文件,大家安装的插件版本一致。

  如果某个插件版本变更。又不想删除package-lock.json文件,重新生成。方法是:npm install plugin@version,及重新安装这个插件,并指定插件的版本,这样,package.json和package-lock.json会自动更新。当然,也可以直接修改package-lock.json文件,这样npm install时,也会安装修改后的版本。但是如果只修改package.json,不修改package-lock.json,npm install还是会安装package-lock.json里的插件版本。

https://www.cnblogs.com/shengulong/p/9463176.html