关于pnpm/npm的一些问题总结

前言

关于node包管理的问题总结,之前都是看很多文章但是没有系统的总结要点,导致很多知识点都忘记了。这篇文章用于总结node包管理的一些问题点。 还有一些关于pnpm的常见问题集也值得看一下

  1. npm@3为什么需要扁平化
  2. 扁平化带来的弊端
  3. pnpm比起npm、yarn的优势是什么
  4. pnpm/npm下载依赖包结构对比,以及不兼容包结构对比
  5. pnpm如何清除掉全局无用的包
  6. 如何将npm迁移到pnpm项目
  7. 在项目里指定pnpm包管理
  8. CI环境下的优化
  9. 幽灵依赖问题
  10. npm dedupe解决的问题
  11. npm pack打包测试版本的压缩包

npm@3为什么需要扁平化

首先来看看npm@2有什么问题。该版本采用了嵌套的形式来解决版本冲突问题。这也导致了新的问题即依赖层级过深以及依赖项无法复用问题。如下A\C两个依赖包都有依赖项B无法复用

├─ A




   ├─ node_modules

   |  ├─ B@1.0.0
└─ C

   ├─ node_modules


   |  ├─ B@1.0.0

为了解决npm@2存在的问题,npm@3实现了依赖扁平化(也没彻底解决可复用以及层级深的问题)。如下A\C两个依赖包都有依赖项B@1.0.0D依赖包依赖于B@2.0.0最终构建的结构如下(B依赖那个版本在平层,那个版本在Node_modules里,取决于解析的先后顺序):

├─ A




├─ B@1.0.0

├─ D@1.0.0
└─ C

   ├─ node_modules


   |  ├─ B@2.0.0

扁平化带来的弊端

  1. 模块可以访问他们不依赖的软件包,幽灵依赖问题
  2. 扁平化依赖树的算法非常复杂
  3. 一些依赖包必须复制到项目的node_modules目录里(不兼容时)
  4. 依赖树的结构不确定(安装顺序对依赖树影响特别大)

pnpm的优势是什么

1.解决了幽灵依赖问题
2.速度: pnpm执行的速度更快、3倍的速度,如下图
alotta-files.svg
3.体积: 将包存储在本地磁盘上,在我们创建的项目里使用硬链接的方式,从global store直接链接依赖。(这也是速度快的原因、对于npm和yarn如果有100个项目使用lodash就会有100份lodash拷贝项目目录里)
实际的依赖存储路径可以通过命令pnpm store path或者查看.modules.yaml文件。 也可以通过pnpm store来修改你需要存储依赖的目录地址
image.png
执行pnpm install,因为之前装过对应的模块,直接从磁盘里面获取
image.png

pnpm/npm下载依赖包结构对比,以及不兼容包结构对比

对于npm@3之前的包结构存在依赖层级过深以及包无法被复用 (A、B依赖包,同时依赖C包,无法被复用).来看看pnpmnpm改进之后的包结构

  • pnpm包结构(非展平依赖树,而是依赖包与其依赖项组合在一起,避免了层级过深问题。依赖包与依赖项是通过符号链接的形式将他们链接在一起。而node_modules的依赖包的文件是来自内容存储的硬链接)
  • pnpm所有依赖的软连接都放置在node_modules/.pnpm/中的对应目录. 把依赖包与依赖包都处于在同一级别避免了循环的软链
  • 硬链接:
  • 符号链接:
    下面以express的accepts包结构为例:
.pnpm
└─ node_modules
    ├─ accepts -> registry.npmmirror.com+accepts@1.3.8
├─ registry.npmmirror.com+accepts@1.3.8
   ├─ node_modules


   |  ├─ accepts // 相关内容
   |  | // 依赖包与其依赖项组合在一起 (以符号链接的形式链接到外层对应的文件,解决了扁平化带来问题.不展开依赖树)
   |  ├─ negotiator -> registry.npmmirror.com+negotiator@0.6.3 
   |  └─ mime-types -> registry.npmmirror.com+mime-types@2.1.35
└─ registry.npmmirror.com+mime-types@2.1.35
   ├─ node_modules
   |  ├─ mime-types // 相关内容
   |  |  // 依赖包与其依赖项组合在一起 (以符号链接的形式链接到外层对应的文件,解决了扁平化带来问题)
   |  ├─ mime-db -> registry.npmmirror.com+mime-db@1.52.0
...

// 不兼容包  (我在项目里安装accepts@1.0.0版本与上面的1.3.0 不兼容)
.pnpm
├─ registry.npmmirror.com+accepts@1.0.0
├─ registry.npmmirror.com+accepts@1.3.8
...
  • npm包结构(扁平化之后)
node_modules
├─ accepts 
├─ mime-types
├─ express
...

// 不兼容 (安装accepts1.0.0 和 express =>  accepts在该包内部)
├─ accepts@1.0.0
├─ express
   ├─ node_modules
   |  ├─ accepts@1.3.8
   

pnpm如何清除掉全局无用的包

使用方法pnpm store prune。它提供了一种用于删除一些不被全局项目所引用到的 packages 的功能。假如之前有一个项目引用了lodash@1.0.0,此时将该项目里的lodash更新为1.1.0。那么全局store目录存储的lodash@1.0.0就不再被引用,应该将它移除掉。(节省本地磁盘开销

pnpm store prune

image.png

如何将npm迁移到pnpm项目

既然pnpm优点这么多,那么如何将已有的npm迁移成pnpm项目也很简单。在项目里执行pnpm import将npm的lock文件生成pnpm-lock.yaml文件。重新pnpm install即可

pnpm import 

image.png

在项目里指定pnpm包管理

为了规范团队,为了防止开发人员使用其他的包管理器npm/yarn install。通过配置npx only-allow ~

npx only-allow 包管理器名称
"scripts": {  
    "preinstall": "npx only-allow pnpm"  
}  

CI环境下的优化

通过执行pnpm ci,相对于npm install命令,他有如下几个不同点:

  1. pnpm ci要求项目必须存在package-lock.jsonnpm-shrinkwrap.json文件
  2. pnpm ci完全依据package-lock.json文件安装依赖。保证团队之间使用一致性的依赖版本
  3. pnpm ci完全依据package-lock.json。因此在安装过程中就不需要解决依赖满足问题以及构造依赖树的问题
  4. pnpm ci会先删除项目中的node_module再安装
  5. pnpm ci无法安装单个依赖包
  6. pnpm ci如果lock文件与package.json冲突,则报错
  7. pnpm ci不会更新lock文件

幽灵依赖问题

假设A包依赖于B包,此时我在项目里只安装了A包,但是我可以在模块里B的语法。 具体可以查看该文章

npm install A


├─ A
└─ B

index.ts
import fn from 'B'  // 合法的

npm dedupe解决的问题

假设A@1.0.0版本依赖B@1.0.0版本、c@1.0.0版本依赖于B@2.0.0。在npm中安装顺序对于构建依赖树的影响特别大. 如下A包先更新

├─ A




├─ B@1.0.0

└─ C

   ├─ node_modules
   |  ├─ B@2.0.0

紧接着我更新了A@2.0.0此时依赖于@B2.0.0.但是由于顶层存在@B1.0.0那么更新A时它的依赖项B会在A的node_module里,且B@1.0.0并没有被销毁。如下结构:

├─ A




   ├─ node_modules

   |  ├─ B@2.0.0
├─ B@1.0.0
└─ C
   ├─ node_modules
   |  ├─ B@2.0.0

上面的依赖结构很明显不是我们想要的,我们想要的应该是如下的结构,如何实现呢,执行npm dedupe即可

├─ A




├─ B@2.0.0
└─ C


npm dedupe减少重复依赖

npm pack打包测试版本的压缩包

有时候我们在开发包的时候,暂时还不想要发布到线上,但是第三方业务有想要先用着,此时就可以通过npm pack打包一个本地版本的压缩包丢给他们即可。 如果自己本地开发就通过npm link来实现

pnpm pack


// 在项目中使用
pnpm install ~(压缩包路径)

image.png

总结

看了很多文章,到最后都忘记,哈哈哈。
这里强烈推荐看一下国外一个博主出的视频讲解。可以使用YouTube中英文字母谷歌插件来看视频。
这里推荐一款快速删除node_modules的脚手架支持多包模式下的删除npkill

参考文献

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYg43Up2' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片