likes
comments
collection
share

被面试官问到包管理器区别了,吓得我赶紧回来看了一下在前端开发过程中,包管理工具是用于管理和安装项目依赖的工具,在版本控制

作者站长头像
站长
· 阅读数 12

在前端开发过程中,包管理工具是用于管理和安装项目依赖的工具,在版本控制、开发协作、构建优化方面有着重要作用,我们目前常见的包管理工具有 npmyarnpnpm

npm

npm 是 Node.js 官方的包管理工具,它在你安装 node 的时候一并安装,在安装完成后可以使用npm -v来查看 npm 当前版本。npm 拥有庞大的开源生态系统,可以方便地查找、安装和管理包(www.npmjs.com/)。

npm 常用指令

  • npm init: 初始化一个 npm 项目,引导创建package.json
  • npm install: 根据项目中 package.json 安装相关依赖
  • npm install [packageName]: 安装指定的包
  • npm uninstall [packageName]: 卸载指定包
  • npm update [packageName]: 更新指定包
  • npm publish: 发布当前包
  • npm search [packageName]: 查询包
  • npm view [packageName]: 查询包的详细信息,版本、依赖、描述等
  • npm outdated: 查看当前有新版本的包
  • npm ls: 查看当前项目所有依赖树
  • npm run [script_name]: 运行 package.jsonscript 定义的脚本
  • npm link: 将当前包链接到全局的 npm 环境中

cnpm

为了解决 npm 下载速度过慢的问题,阿里巴巴的淘宝团队提供的一个 npm 镜像。以提高下载速度和稳定性。使用以下命令进行配置淘宝镜像:

npm config set registry https://registry.npmmirror.com

npx

npx 是 npm5.2 版本引入的工具,用于执行 npm 包命令,相比 npm,npx 会自动安装依赖包并执行某个命令,无需预先全局或本地安装某个命令行工具。举个栗子 🌰:

如果你想使用 create-react-app 来创建一个新的 React 项目,你需要首先全局安装这个包:

npm install -g create-react-app
create-react-app my-app

如果你的有些项目 create-react-app 的另外一个版本,这时候会导致版本冲突,也会造成全局污染。npx 的出现解决了这些问题。使用 npx,你可以直接运行 create-react-app 而无需先全局安装它:

npx create-react-app my-app

当执行这个命令的时候会执行以下步骤:

  1. npx 先检查你的项目是否已经安装了create-react-app,如果安装了,则使用项目中的版本
  2. npx 会从 npm 仓库中临时下载create-react-app的最新版本,并安装到临时的 node_modules 文件夹中然后运行命令来创建一个 react 项目
  3. 当创建项目的命令执行完成后,npx 会清理临时安装的create-react-app和相关的 node_modules文件夹

yarn

由 Facebook、Google、Exponent 和 Tilde 联合推出的一个新的 JS 包管理工具,为了解决 npm 的性能和安全性问题。

npm install yarn -g

优点:通过并行下载和本地缓存来提高性能,可以更快地安装项目的依赖项。默认生成一个 yarn.lock 文件来锁定版本(类似于 npm 的 package-lock.json),确保在不同环境中安装的依赖项版本一致,并且通过验证依赖项的来源和内容来提高安全性,检查每个依赖项的哈希值,并提供签名验证功能。

yarn 常用指令

  • yarn init: 与 npm 一样创建package.json
  • yarn install: 根据项目中 package.json 安装相关依赖
  • yarn add [packageName]: 安装指定的包并添加到dependencies
  • yarn remove [packageName]: 删除指定的包,并更新 package.jsonyarn.lock

大多命令和 npm 相同。

pnpm

pnpm 由 npm 和 yarn 衍生而来,解决了 npm 和 yarn 在磁盘空间和依赖管理方面的一些问题。

pnpm 是如何节省磁盘空间的?

  1. 共享依赖:当多个项目使用相同的依赖的时候,pnpm 只会在磁盘上保留一份依赖。
  2. 符号链接:当一个项目安装了某个包的时候 pnpm 会在项目的 node_modules 目录下创建一个符号链接指向全局的依赖目录,这样多个项目可以共享一个依赖而不是每个项目都拥有一份独立的依赖副本。
  3. 快照:为了确保项目在不同环境下的一致性,pnpm 将每个项目的依赖信息记录在 pnpm-lock.yaml 的锁文件中。该文件包含了项目所需的依赖以及版本信息,当其他开发者在不同的环境下安装相同的项目时,pnpm 会根据锁文件中的信息安装相同的依赖,从而保证依赖的一致性。

pnpm 的常用指令跟 npm 基本一致,就不再赘述。

npm、yarn、pnpm 区别

我们从 node_modules 的目录结构来看看区别:

早期 npm 的嵌套结构

早在 npm@3 之前,所有的包是附带各自的node_modules的嵌套结构,如下:

node_modules
└─ package1
   ├─ index.js
   ├─ package.json
   └─ node_modules
      └─ package3
         ├─ index.js
         └─ package.json
└─ package2
   ├─ index.js
   ├─ package.json
   └─ node_modules
      └─ package3
         ├─ index.js
         └─ package.json

比如我现在依赖中需要 package1 和 package2,但是这两个包都依赖 package3 的包,但是这时候的 package3 会存在需要依赖它的包中,这样会导致 package3 的冗余,node_modules的体积特别大,而且如果包一个依赖一个会造成文件路径特别深,并且 windows 有最大路径长度限制,所以在对于一些依赖层级比较深的包就会产生问题。这时候 yarn 就针对该问题做了处理。

yarn 的扁平结构

为了解决上述嵌套层级深的问题,yarn 采用扁平化来解决。(ps.npm3+以上的版本也是使用扁平化的方式管理 node_modules)

node_modules
└─ package3
   ├─ index.js
   └─ package.json
└─ package1
   ├─ index.js
   ├─ package.json
└─ package2
   ├─ index.js
   ├─ package.json

将 package3 包进行提升,但是依赖包有多个版本的时候只会提升一个,其余的版本依旧会存在多个。但这种扁平化包管理的方式经常会造成幽灵依赖问题。

幽灵依赖:我们使用 yarn 有时会出现安装了一些不需要的或者不正确的依赖包的情况。这些依赖包在项目中没有被显式地引用或使用,但仍然存在于 node_modules 目录中,占用了项目的存储空间。

这时候 pnpm 解决了这些问题。

pnpm 的软硬链接

pnpm 采用了软连接和硬链接的方式解决以上存在的问题,软硬连接是操作系统提供的机制。

  • 硬链接是指在同一个文件系统中,将一个文件名关联到一个已经存在的文件上,使得该文件名也可以访问该文件。硬链接与原文件共享 inode,即它们有相同的 inode 号和相同的 device 号。因此,对于硬链接和原文件来说,它们的访问权限、所有者、大小等属性都是相同的。(可以理解为对原文件起了一个别名,本质是同一个文件)
  • 软链接(也称符号链接)是指在不同的文件系统之间,将一个文件名关联到另一个文件上,使得该文件名也可以访问该文件。软链接与原文件不共享 inode,它们有不同的 inode 号和 device 号。因此,对于软链接和原文件来说,它们的访问权限、所有者、大小等属性可能不同。(它包含了到原文件的路径信息,本质不是同一个文件)

pnpm 将所有的依赖放在全局的 store 中,然后硬连接到node_modules/.pnpm下,官方的解释如下:

被面试官问到包管理器区别了,吓得我赶紧回来看了一下在前端开发过程中,包管理工具是用于管理和安装项目依赖的工具,在版本控制

使用 npm 时,依赖每次被不同的项目使用,都会重复安装一次。而在使用 pnpm 时,依赖会被存储在内容可寻址的存储中,所以:

  1. 如果你用到了某依赖项的不同版本,只会将不同版本间有差异的文件添加到仓库。
  2. 所有文件都会存储在硬盘上的某一位置。当软件包被被安装时,包里的文件会硬链接到这一位置,而不会占用额外的磁盘空间。这允许你跨项目地共享同一版本的依赖。

这样就大大节省了磁盘空间,并且使用符号链接没有使用扁平化的目录所以不会存在幽灵依赖。

这些包就是软链接。

被面试官问到包管理器区别了,吓得我赶紧回来看了一下在前端开发过程中,包管理工具是用于管理和安装项目依赖的工具,在版本控制

我们可以使用命令查看一下这些所链接的文件位置,我们输入ll -a node_modules命令可以查看:

被面试官问到包管理器区别了,吓得我赶紧回来看了一下在前端开发过程中,包管理工具是用于管理和安装项目依赖的工具,在版本控制

这些链接文件位置是在node_modules/.pnpm文件夹中。

pnpm 也提高了安装速度,分三步:

  1. 依赖解析:仓库中没有的依赖都被识别并获取到仓库。
  2. 目录结构计算:node_modules目录结构是根据依赖关系计算的。
  3. 链接依赖项:所有剩余的依赖项都会从存储中提取并硬链接到node_modules

怎么解释 pnpm 为什么安装的快?可以这么回答:

  1. pnpm 只需要下载必需的模块,不会下载整个依赖树(上面提到的硬链接)
  2. 并行下载模块:意味着可以多个文件同时传输,加快整体安装速度。
  3. 使用硬链接:pnpm 的 node_modules 布局使用符号链接来创建依赖项的嵌套结构。这种基于内容寻址的方式不会重复安装同一个包,即使在不同项目之间也可以极大程度地复用之前版本的代码。例如,如果多个包都依赖 express,pnpm 只会在一个地方写入 express 的代码,其他包则通过硬链接引用这部分代码。
  4. 快速查找和依赖解析:pnpm 内部机制对于依赖的查找和解析进行了优化,使得在安装过程中能够快速定位并处理所需的依赖项。
转载自:https://juejin.cn/post/7380771735682236435
评论
请登录