npm和yarn(一)

早期的npm(npm v2)
  • 在安装依赖的时候会将依赖放到 node_modules文件中;
  • 如果某个包A依赖于B,B作为间接依赖,会被安装到A的文件夹的node_modules中,递归进行,直到子依赖中不再依赖其他模块;
    优点:层级结构明显,每次安装的目录结构都是相同的

存在的问题

  • 如果项目过大,必然会形成一棵巨大的依赖树,嵌套层级非常深。
  • 不同层级中存在相同的模块,导致大量冗余。
  • 在windows系统中,文件路径最大长度为260个字符,嵌套层级过深可能导致不可预知的问题。


扁平结构

为解决上面的问题 npm3.x版本做了一次较大的更新,将早期的嵌套结构改为了扁平结构:

  • 安装模块时,不管其是依赖还是子依赖的依赖,优先将其安装在 node_modules根目录
  • 当安装到相同模块时,判断已安装的模块是否符合新的模块的版本范围,符合则跳过,不符合则在当前模块的node_modules下安装该模块。
{
  "name": "my-app",
  "dependencies": {
    "buffer": "^5.4.3",
    "ignore": "^5.1.4",
     "base64-js": "1.0.1",
  }
}
{
  "name": "buffer",
  "dependencies": {
    "base64-js": "^1.0.2",
    "ieee754": "^1.1.4"
  }
}

npm 3.x版本带来了新的问题。
由于在执行 npm install 的时候是按照 package.json 里依赖的顺序依次解析,依赖包在 package.json 的放置顺序则决定了 node_modules 的依赖结构,依赖结构的不确定性可能会给程序带来不可预知的问题。

Lock文件

为了解决npm install的不确定性问题,npm 5.x 版本中新增了package-lock.json文件,安装方式还是沿用npm 3.x的扁平化方式。package-lock.json的作用是锁定依赖结构,即只要项目目录下有package-lock.json,那么每次执行 npm install后生成的node_modules目录结构一定是完全相同的
例如,我们有如下的依赖结构:

{
  "name": "my-app",
  "dependencies": {
    "buffer": "^5.4.3",
    "ignore": "^5.1.4",
    "base64-js": "1.0.1",
  }
}
{
  "name": "my-app",
  "version": "1.0.0",
  "dependencies": {
    "base64-js": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.0.1.tgz",
      "integrity": "sha1-aSbRsZT7xze47tUTdW3i/Np+pAg="
    },
    "buffer": {
      "version": "5.4.3",
      "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.3.tgz",
      "integrity": "sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==",
      "requires": {
        "base64-js": "^1.0.2",
        "ieee754": "^1.1.4"
      },
      "dependencies": {
        "base64-js": {
          "version": "1.3.1",
          "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
          "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g=="
        }
      }
    },
    "ieee754": {
      "version": "1.1.13",
      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
      "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="
    },
    "ignore": {
      "version": "5.1.4",
      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz",
      "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A=="
    }
  }
}

最外面的两个属性 nameversionpackage.json 中的 nameversion ,用于描述当前包名称和版本。

dependencies 是一个对象,对象和 node_modules 中的包结构一一对应,对象的 key 为包名称,值为包的一些描述信息:

  • version:包版本 —— 这个包当前安装在 node_modules 中的版本
  • resolved:包具体的安装来源
  • integrity:包 hash 值,基于 Subresource Integrity 来验证已安装的软件包是否被改动过、是否已失效
  • requires:对应子依赖的依赖,与子依赖的 package.jsondependencies的依赖项相同。
  • dependencies:结构和外层的 dependencies 结构相同,存储安装在子依赖 node_modules 中的依赖包。
npm的缓存机制

缓存位置: /Users/xxx/.npm


  • content-v2 目录用于存储tar包的缓存
  • index-v5 目录用于存储tar包的hash
  • npm在执行安装时,可以根据package-lock.json中存储的intergiryversionname生成一个唯一的key对应到index-v5目录下的缓存记录,从而找到tar包的hash,然后再根据hash取找缓存的tar包直接使用
npm的安装流程
  1. 执行 npm install 后,首先检查和获取npm的配置,优先级为:

项目级的.npmrc文件 > 用户级的.npmrc文件 > 全局的.npmrc文件 > npm内置的.npmrc 文件

  1. package-lock.json文件:
  • 从 npm 远程仓库(registry)获取包信息
  • 根据 package.json 构建依赖树,构建过程:
    1)构建依赖树时,不管其是直接依赖还是子依赖的依赖,优先将其放置在 node_modules 根目录。
    2)当遇到相同模块时,判断已放置在依赖树的模块版本是否符合新模块的版本范围,如果符合则跳过,不符合则在当前模块的 node_modules 下放置该模块。
    3)在缓存中依次查找依赖树中的每个包,不存在缓存就从 npm 远程仓库下载包(下载压缩包后,存放到 ~/.npm 目录),将包按照依赖结构解压到node_mudules
    4)生成 lock 文件
  1. package-lock.json 文件:

检查 package.json 中的依赖版本是否和 package-lock.json 中的依赖有冲突。
如果没有冲突,直接跳过获取包信息、构建依赖树过程,开始在缓存中查找包信息,后续过程相同

yarn

当npm还处于v3时期的时候(当时还没有package-lock.json),yarn作为一个新的包管理工具出现,解决了npm的一些问题(lock、缓存等问题,npm后续也进行了优化)

  1. 确定性: 用过yarn.lock 机制,即使是不同的安装顺序,相同的依赖关系在任何环境和容器中都以相同的方式安装。
  2. 模块扁平化:将不同版本的依赖包,按照一定的策略,归结为单个版本,避免冗余。
  3. 网络性能:yarn采用了请求排队的理念,类似于并发池连接,能够更好的利用网络资源,同时引入了一种安装失败的重试机制
  4. 采用缓存机制,实现了离线模式
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容