如何使用 pnpm 和 pnpm workspace?
什么是软连接和硬链接(Symbolic Link、Hard Link)
【硬连接】
命令:ln file1 file2
限制:不能跨分区;文件夹无效。
作用:实现对file1的一个硬连接。不同于拷贝(复制)。
效果:修改file1,file2会变;修改file2,file1会变。删除file1后file2任然存在且可用(数据任然为file1的数据)。多个硬连接,也始终只有一个存储区块。
原理:每对file1增加一个硬连接,系统对file1的对应的硬盘数据节点的连接数加一。当删除file1或file2等其它硬连接时,对磁盘对应的数据节点连接数减一,只有当连接数为0时,才真正的删除数据。
- 硬链接实际上是为文件建一个别名,链接文件和原文件实际上是同一个文件。可以通过ls -i来查看一下,这两个文件的inode号是同一个,说明它们是同一个文件。
【软连接】
命令:ln -s file1 file2
作用:实现对file1的一个软连接。
限制:可以跨分区;文件夹无效。
效果:修改file1,file2会变;修改file2,file1会变。删除file1后file2变为不可用。若强行编辑file2并保存,系统会生成文件file1,内容为file2编辑的内容。若对file2再建立软连接file3,实际效果为file3为file1的软连接。
原理:类似于windows的快捷方式。
- 通过软链接建立的链接文件与原文件并不是同一个文件,相当于原文件的快捷方式。具体理解的话,链接文件内存储的是原文件的inode,也就是说是用来指向原文件文件,这两个文件的inode是不一样的。
【复制】
命令:cp file1 file2
作用:实现对file1的一个拷贝。
限制:可以跨分区,文件夹有效。
效果:修改file1,对file2无影响;修改file2,对file1无影响。删除file1,对file2无影响;删除file2,对file1无影响。
原理:磁盘存储空间的一个拷贝。
特点
硬链接的特点是这样的:
- 它会在链接文件处创建一个和被链接文件一样大小的文件,类似于国外网站和国内镜像的关系,
- 硬链接占用的空间和被链接文件一样大(其实就是同一片空间)
- 修改链接文件和被链接文件中的其中一个,另外一个随之同样发生变化
- 硬链接的对象不能是目录,也就是说被链接文件不能为目录
- 硬链接的两个文件是独立的两个引用计数文件,他们共用同一份数据,所以他们- 的inode节点相同
- 删除硬链接中的任意一个文件,另外一个文件不会被删除。没有任何影响,链接文件一样可以访问,内容和被链接文件一模一样。
软链接的特点:
- 软连接的链接文件就是一个基本单元大小的文件,一般为3B,和被链接文件的大小没有关系
- 软链接的链接文件中存储的是被链接文件的元信息,路径或者inode节点
- 软连接的连接文件是一个独立的文件,有自己的元信息和inode节点
- 删除软链接的链接文件,被链接文件不会受到任何影响
- 删除软链接的被链接文件,链接文件会变成红色,这时打开链接文件会报错,报找不到被链接的文件这种错误
- 软链接可以链接任何类型的文件,包括目录和设备文件都可以作为被链接的对象
复制的特点:
- 复制产生的文件是一个独立的文件,有自己的元信息和inode节点
- 删除或修改复制文件,对原文件不会产生任何影响,反过来也是一样的
- 复制可以复制文件,也可以复制目录
原文链接:https://blog.csdn.net/geerniya/article/details/79093301
Linux命令之ln(link files)
- 通过 ln -s 创建一个软链接(符号链接)—>
ln -s source source1
- 通过 ln 创建一个硬链接 —>
ln source source1
- 复制 cp 复制文件 —>
cp source source1
1
2
3
4
5
6
7
8
9
10
11
12
13
14# 在当前路径下创建文件demo
touch demo
# 给demo文件创建链接文件名为ldemo
ln -s demo ldemo
# 修改ldemo链接文件的内容
ls > ldemo
# 查看demo文件的内容是否同样变化
cat demo
# 修改 demo文件内容
ls -l > demo
# 查看ldemo链接文件内容是否同样变化
cat ldemo
# 删除原文件,链接文件会失效
rm demo
在Linux系统中存在两种链接文件方式
软链接(类似windows下的快捷方式)
1 | ln -s 原文件名 链接文件名 |
如果文件被删除,则软链接文件失去指向,变为不可用
硬链接(类似我们js 的引用关系)
1 | ln 原文件名 链接文件名 |
如果文件被删除,由于硬链接文件直接指向内容,因此不受影响
ls -lh
ls 使用方式
1 | ls # 仅列出当前目录可见文件 |
pnpm 工具
pnpm == p(performant) + npm,代表高性能的 npm
当使用 npm 或 Yarn 时,如果你有 100 个项目使用了某个依赖(dependency),就会有 100 份该依赖的副本保存在硬盘上。 而在使用 pnpm 时,依赖会被存储在内容可寻址的存储中
- 如果你用到了某依赖项的不同版本,只会将不同版本间有差异的文件添加到仓库。 例如,如果某个包有100个文件,而它的新版本只改变了其中1个文件。那么 pnpm update 时只会向存储中心额外添加1个新文件,而不会因为仅仅一个文件的改变复制整新版本包的内容。
- 所有文件都会存储在硬盘上的某一位置。 当软件包被被安装时,包里的文件会硬链接到这一位置,而不会占用额外的磁盘空间。 这允许你跨项目地共享同一版本的依赖。
- 安装速度很快,节省磁盘空间,还有安全性
pnm 项目初衷pnpm 为何节省空间
- 它解决了 npm\yarn 平铺 node_modules 带来的依赖项重复的问题
.pnpm
虚拟存储目录。什么是平铺?
假设存在依赖的依赖1
2
3
4
5
6--- package-A
--- lodash@4.0.0
--- package-B
--- lodash@3.0.0
--- package-C
--- lodash@3.0.0
在 npm\yarn 中 lodash@3.0.0会被多次安装,就造成空间浪费
1 | ./node_modules/package-A |
- pnpm 就用软连接的形式,避免了 doppelganger(外表非常相似的)(幽灵依赖) 节省空间
如果用pnpm 安装1
2
3
4
5
6
7./node_modules/package-A -> .pnpm/package-A
./node_modules/package-B -> .pnpm/package-B
./node_modules/package-C -> .pnpm/package-C
.pnpm/node_modules/lodash@4.0.0 -> .pnpm/lodash@4.0.0
.pnpm/node_modules/lodash@3.0.0 -> .pnpm/lodash@3.0.0
.pnpm/lodash@3.0.0
.pnpm/lodash@4.0.0
pnpm-store
储存在 pnpm-store
安装 linux_whale_lite 依赖包大小的对比
npm 294MB
pnpm 281MB
pnpm-lock.yaml 的作用?
pnpm生成的pnpm-lock.yaml文件
pnpm-lock.yaml 是一个文件,它存储了一个包的所有依赖的版本号。
要始终被提交到git 仓库,主要是:
- 在 CI 和生产环境中能够更快地完成安装,因为解析依赖的过程可以被跳过。
- 开发,测试和生产环境之间强制执行一致的安装和解析方案,这意味着测试和生产中使用的包将与您开发项目时完全相同
.npmrc 的作用?
pnpm 从命令行、环境变量和 .npmrc 文件中获取其配置
pnpm config 命令可用于更新和编辑 用户和全局 .npmrc 文件的内容。
四个相关文件分别为:
- 每个项目的配置文件(/path/to/my/project/.npmrc)
- 每个工作区的配置文件(包含 pnpm-workspace.yaml 文件的目录)
- 每位用户的配置文件( ~/.npmrc )
- 全局配置文件( /etc/npmrc )
常用配置 shamefully-hoist 和 strict-peer-dependencies
shamefully-hoist
默认值: false
类型:Boolean
默认情况下,pnpm 创建一个半严格的 node_modules,这意味着依赖项可以访问未声明的依赖项,但 node_modules 之外的模块不行。 通过这种布局,生态系统中的大多数的包都可以正常工作。 但是,如果某些工具仅在提升的依赖项位于根目录的 node_modules 时才有效,您可以将其设置为 true 来为您提升它们。
strict-peer-dependencies
默认值: true
类型:Boolean
如果启用了此选项,那么在依赖树中存在缺失或无效的 peer 依赖关系时,命令将执行失败。
因为 pnpm 不能自动检测 peer 依赖关系,所以必须手动指定它们。
Monorepo 及 工作空间(Workspace)
Monorepo
Monorepo
由两个单词组成,Mono
指的是单个(single),repo
指的是项目存储(Repository),合起来意思就是说,大量的项目存储在单一的库中,用人话讲就是,不同的项目都写在一个 git
库里
Monorepo优点
- 不同项目之间,如果需要复用相同的组件或者方法,就可以很方便的引用,同时,这些公用方法一旦修改了,其他项目的相应逻辑交互也都更新了,不同在担心忘了安装或者更新
- 同时也比单纯的 复制黏贴 要更科学,项目的颗粒度可以更小,更容易维护,更容易扩展,更容易维护
- 发包时,可以根据子项目独立的包发布,像 vue3 reactive 模块可以单独被安装使用
Monorepo缺点
- 子项目不好管控权限问题,安全性不高,
Workspace 协议 (workspace:)
通过别名引用 workspace 包
1 | "@vue": "workspace:./packages", |
通过这个形式可以把packages 下的子包都打到 node_modules 下,这样就可以直接使用
1
import { isFunction } from '@vue/shared'
或者使用link 的模式
1
"@vue": "link:./packages",
link:./packages
等同于 workspace:./packages
将一个 monorepo 的工作空间中的本地可用package链接到 node_modules 中,而不是从注册表重新下载。 这个功能模拟类似于 yarn workspaces。
1 | "@vue/reactivity": "link:packages/reactivity", |
- 或者在自己的分包里
pnpm add @nova/utils 也会添加到依赖上。也可以使用yarn workspace 命令来创建一个新的工作空间
在package.json 中加入1
2
3"workspaces": [
"packages/*"
]
link-workspace-packages
Default: true
Type: true, false, deep
当它设置为 deep 时,本地package也可以被子依赖项链接到
将一个 monorepo 的工作空间中的本地可用package链接到 node_modules 中,而不是从注册表重新下载。 这个功能模拟类似于 yarn workspaces。
建议在.npmrc
文件配置--link-workspace-packages
package.json文件说明解释
- npm模块的完整的版本号一般是【主版本 . 次要版本 . 补丁版本】,一般情况下,次要版本号发生改变的话,表示程序有重大更新。
~表示版本范围
- 若主版本号不为0,则允许次要版本号+补丁版本号升级
~2.3.4 主版本+次要版本+补丁版本 2.3.4 <= version < 2.4.0
~2.3 主版本+次要版本 2.3.0 <= version < 2.4.0
~2 主版本+次要版本 2.0.0 <= version < 3.0.0
主版本号:当你做了不兼容的 API 修改
次版本号:当你做了向下兼容的功能性新增
修订号:当你做了向下兼容的问题修正使用^表示版本范围
- 若主版本号不为0,则允许次要版本号+补丁版本号升级
- 若主版本号为0,次要版本号不为0,则允许补丁版本号升级;
^1.3.4 主版本号不为0 1.3.4 <= version < 2.0.0
^0.2.3 主版本号为0,次要版本号不为0 0.2.3 <= version < 0.3.0
^0.0.3 主版本号+次要版本号均为0 0.0.3 <= version < 0.0.4
peerDependencies
peerDependencies
的目的是提示主环境去安装满足插件peerDependencies
所指定依赖的包,然后在插件import
或者require
所依赖的包的时候,永远都是引用宿主环境统一安装的npm包,最终解决插件与所依赖包不一致的问题。
- 本文作者: Littleki
- 本文链接: https:/littleki.gitee.io/2022/07/25/分享会/pnpm使用/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!