从软链接&硬链接理解前端包管理工具

·  阅读 601

大家好,今天从计算机文件系统的软硬链接(hard-link symbolic-link)入手,了解前端的包管理工具。为什么从这个角度了解呢?了解软硬链接有什么用呢,可以带着下边的几个问题思考一下

  • npm/yarn link 是干嘛的
  • pnpm 为什么是 performant(高性能的) npm

文件系统:Window2000及以上采用NTFS和Linux7及以上采用的XFS

一、概念和实操验证

硬链接(hard link,也称链接)就是一个文件的一个或多个文件名。再说白点,所谓链接无非是把文件名和计算机文件系统使用的节点号链接起来。因此我们可以用多个文件名与同一个文件进行链接,这些文件名可以在同一目录或不同目录。

软链接文件有类似于Windows的快捷方式。它实际上是一个特殊的文件。在符号连接中,文件实际上是一个文本文件,其中包含的有另一文件的位置信息。

1. Linux 下的软硬链接实操

以下命令是我在Linux 虚拟机中的操作

  1. 第一步新建testfile文件;
  2. 第二步给文件输入内容'有朋自远方来';
  3. 第三步通过ln 在同文件路径下建立硬链接文件hardtestfile;
  4. 第四步修改被硬链接的文件,加上'虽远必诛';
  5. 第五步查看源文件testfile 内容和被硬链接的文件同步被修改了\
[wyq@localhost f]$ touch testfile //新建testfile文件
[wyq@localhost f]$ echo '有朋自远方来'>testfile
[wyq@localhost f]$ cat testfile有朋自远方来
[wyq@localhost f]$ ln testfile hardtestfile
[wyq@localhost f]$ lshardtestfile  testfile
[wyq@localhost f]$ echo '虽远必诛'>>hardtestfile
[wyq@localhost f]$ cat testfile // testfile内容变化
有朋自远方来 虽远必诛
复制代码

2. Linux 下的软链接

在上边已经建立testfile文件的基础上

  1. 我们执行ln -s testfile softtestfile // ln -s 建立testfile的软链接
  2. 修改软链接的文件内容
  3. echo '不亦乐乎'>>softtestfile
[wyq@localhost f]$ ln -s testfile softtestfile //新建testfile文件
[wyq@localhost f]$ cat softtestfile有朋自远方来 虽远必诛
[wyq@localhost f]$ lshardtestfile  testfile
[wyq@localhost f]$ echo '不亦乐乎'>>softtestfile
[wyq@localhost f]$ cat softtestfile // testfile内容变化
有朋自远方来 虽远必诛 不亦乐乎
复制代码

我们在通过 ls -li

[wyq@localhost f]$ ls -litotal 819446343 -rw-rw-r--. 2 wyq wyq 45 Jan 17 19:37 hardtestfile
19446346 lrwxrwxrwx. 1 wyq wyq  8 Jan 17 19:27 softtestfile -> testfile
19446343 -rw-rw-r--. 2 wyq wyq 45 Jan 17 19:37 testfile
复制代码

发现不论是源文件还是软、硬链接文件,一个发生修改,其他数据也都会发生改变

硬链接的特点

  1. 不论是修改源文件(testfile),还是修改硬链接文件(hardtestfile),另一个文件的数据都会改变
  2. 不论是删除源文件,还是删除硬链接文件,只要还有一个文件存在,这个文件(inode 号是19446343的文件)都可以被访问,硬链接不会建立新的 inode 信息,也不会更改 inode 的总数。 
  3. 硬链接不能跨文件系统(分区)建立,因为在不同的文件系统中,inode 号是重新计算的。
  4. 硬链接不能链接目录,因为如果给目录建立硬链接,那么不仅目录本身需要重新建立,目录下所有的子文件,包括子目录中的所有子文件都需要建立硬链接,这对当前的 Linux 来讲过于复杂。

不同的是软链接会真正建立自己的 inode 索引和 block,所以软链接和源文件的 inode 号(19446346)是不一致的,而且在软链接的 block 中,写的不是真正的数据,而仅仅是源文件的文件名及 inode 号,所以软链接和硬链接在原理上最主要的不同在于:

硬链接不会建立自己的 inode 索引和 block(数据块),而是直接指向源文件的 inode 信息和 block,所以硬链接和源文件的 inode 号是一致的;而软链接会真正建立自己的 inode 索引和block,所以软链接和源文件的 inode 号是不一致的,而且在软链接的 block 中,写的不是真正的数据,而仅仅是源文件的文件名及 inode 号

3. Window下的软、硬链接

可使用mklink,具体指令就不再赘述了,可自行搜索

不过window系统下有三个链接概念hard-link、Junction、symbolic-link,可查阅文末的参考文档1

二、NPM/Yarn Link

我们了解hard linkSymbolic link之后,再来看看npm link是干什么的,npm link 是npm 的一个命令,用来建立文件的软链接(symbolic-link)

我们用一个场景来实操一下,本质其实就是关联两个文件夹,比如调试npm包或者是写webpack loader这些场景等,都可以使用npm link 做文件夹的关联

步骤如下

  1. 在C盘新建一个文件夹 link(可以当作看作是npm包的工程),npm init 初始化package.json("name": 'testnpmlink')
  2. 进入到link目录下 执行 npm link,就会生成一个全局的软链接
  3. 项目工程(要加载使用link工程)目录,执行  npm  link  testnpmlink 

图片

图片 步骤1、2-全局的软链接

图片

图片

步骤3的结果-项目中的安装

图片

通过截图可以看到在node.js的安装目录和项目中的node_modules都可以修改调试。理解了上边的软链接的概念和特点,就清楚npm link做了哪些事

三、Why Pnpm

Pnpm 为什么是 performant(高性能的) npm

pnpm内部使用基于内容寻址的文件系统来存储磁盘上所有的文件,这个文件系统出色的地方在于:

不会重复安装同一个包。用 npm/yarn 的时候,如果 100 个项目都依赖 lodash,那么 lodash 很可能就被安装了 100 次,磁盘中就有 100 个地方写入了这部分代码。但在使用 pnpm 只会安装一次,磁盘中只有一个地方写入,后面再次使用都会直接使用 hardlink。 

即使一个包的不同版本,pnpm 也会极大程度地复用之前版本的代码。举个例子,比如 lodash 有 100 个文件,更新版本之后多了一个文件,那么磁盘当中并不会重新写入 101 个文件,而是保留原来的 100 个文件的 hardlink,仅仅写入那一个新增的文件。

神三元

总结来说就是安装速度很快,节省磁盘空间,还有安全性等,具体可参考 这篇文章

本文还是主要介绍pnpm 的连接方式,上边也提到了pnpm只会安装一次,后边的使用都是通过hardlink的方式,看如下截图

图片

总结上边的两个截图我们可以总结来说是包含两方面的信息

1. CAS(Content-addressable store)

内容寻址存储,它是一种存储信息的方式,根据内容而不是位置进行检索信息的存储方式。

2. Virtual store

虚拟存储,指向存储的链接的目录,所有直接和间接依赖项都链接到此目录中,项目当中的.pnpm目录。

我们安装express之后,提示该packages已经从内容寻址的储存地址被硬链接到一个虚拟的储存位置

下边分别列出来了Content-addressable store是在 我的这个目录下

C:/Users/wyq/.pnpm-store/v3

Virtual store 是在实际项目的node_modules/.pnpm下

图片

下边截图是node_modules通过符号链接显示的布局,node_modules中每个包的每个文件都是来自内容可寻址存储的硬链接

图片

这里稍微提一下,pnpm文档也提到的一个点,就是在项目中使用pnpm遇到问题时,官方其中一个不太推荐的解决方案是使用shamefully-hoist选项。这会创建一个扁平的node_modules结构,跟npm/yarn类似的hoist机制,hoist机制的问题可以自行了解下。

这种做法 is shamefully ,这个词挺有意思,闲扯一下:我个人理解有两层意思吧,一层是pnpm官方的歉意, pnpm跟npm/yarn不一样的思路,在遇到实在解决不了的问题,实在抱歉;另一层意思是我能非扁平化解决依赖问题,你再使用hoist,你就太"无耻"了。

图片

再说下pnpm跟硬链接有关系的一个问题,就是由于硬链接的特点,不能跨多个驱动器或文件系统工作,分两种情况:

1. 存储路径已指定

pnpm config set store-dir /path/to/.pnpm-store
复制代码

如果我们在磁盘C上执行 pnpm install,则 pnpm 存储必须位于磁盘 C。如果 pnpm 存储位于磁盘D,则所有需要的包将被直接复制到项目位置而不是链接。这个严重的抑制了 pnpm 的存储和性能优势。

2. 存储路径未指定

则会创建多个存储(每个驱动器或文件系统一个)。如果在磁盘C上pnpm install,则存储将在C的文件系统根目录下的 .pnpm-store下被创建。如果在磁盘D上安装运行,将会在D上的 .pnpm-store处创建一个独立的存储。项目仍将保持 pnpm 的优势,但每个驱动器可能有冗余包。

最后重要提醒

get hands dirty! get hands dirty! get hands dirty!

参考文档

1. https://docs.microsoft.com/en-us/windows/win32/fileio/hard-links-and-junctions2. https://docs.microsoft.com/en-us/windows/win32/fileio/creating-symbolic-links3. https://pnpm.io/
复制代码

图片

分类:
前端
标签:
分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改