一文帶你深度理解 pnp

前言

全局 store

和 npm、 yarn 包管理器一樣。pnpm 也有緩存目錄, 不過他的緩存目錄是 全局的, 在 pnpm 中稱之爲  store

那麼 pnpm  store 存放的路勁是在哪裏    輸入下面命令

pnpm store path

可以得到當前環境下的 pnpm store 目錄路徑 ,注意 mac 和 windows 其實 對應的 目錄是不一樣的。 這一點作爲開發者我們不需要關心。 那麼 pnpm store 中 存放的是什麼類型的文件呢???

這裏拿我本地的 pnpm path 去帶搭建實際看下

輸入 pnpm store path

得到如下圖

然後點擊去 看 pnpm store 全局存的到底是啥

上圖是我們全局目錄下 pnpm 的目錄結構。

我們在全局目錄裏存放的不是 npm 包的源碼,而是 hash 文件,這裏採用了基於文件內容尋址方案。

簡單來說就是文件內容被加密成了 64 位 hash 值,hash 值都是唯一的,如果文件內容不變,hash 值也不會變。

這種全局 store 緩存的特性 ,非常適合 npm 包版本, 這裏我舉一個例子, 比如 我們常用的 axios 。全局 store 安裝的 版本是 3.0.1,

在某一次 pnpm install 的時候, 由於 package.json 的語義化版本,導致 axios 升級了 3.0.2 其實可能對於他而言 只是 改了一個文件,

那 pnpm 在更新全局 store 的時候, 對於 axios 其他部分的 hash 是不變的, 因爲 內容沒有變化, 只會變動哪些改變的 hash。這個也是 pnpm install 安裝快速的原因, 一定程度上,也節省了磁盤空間。

這裏我在講解一個命令

pnpm store  prune

他是刪除全局 store 中未引用的包, 還是上文中的一個問題 axios 從 3.0.1 升級 3.0.2 了 那麼對於我們項目來說 3.0.1 的包 是不是屬於是 未引用了。

axios 會有這樣的情況, 其他的包版本 也會有這樣的情況。不定時的清除 未引用的包 , 只要你的磁盤夠大,其實這件事本身沒有影響。

運行 pnpm store prune 是無害的,對您的項目沒有副作用。如果以後的安裝需要已經被刪除的包,pnpm 將重新下載他們。

最好的做法是 pnpm store prune 來清理存儲,但不要太頻繁。有時,未引用的包會再次被需要。這可能在切換分支和安裝舊的依賴項時發生,在這種情況下,pnpm 需要重新下載所有刪除的包,會暫時減慢安裝過程。虛擬 store

首先我問大家一個問題, 什麼是 虛擬 store???

虛擬 store (前提是使用 pnpm 進行前端的項目包管理)  就是 node_modules 中. pnpm 文件夾

OK, 知道了這個是 虛擬 store, 虛擬 store 解決了什麼問題???

這個其實是社區上非常有名的 npm 包問題 ——  幽靈依賴

我這裏用一句話概括一下, 其實就是 訪問了項目中 本不該存在  "dependencies":   中的依賴,  那他爲什麼可以訪問??是因爲 yarn 會將當前包的 依賴 平鋪到 node_modules 中, 導致了你在 node_modules 可以訪問不屬於本項目的依賴 , 這種行爲是極具危險性的, 非常的不安全, 不利於穩定生產。

pnpm 的 node_modules 結構非常的簡單

|-- animate

    |-- 各種包...

    |-- .bin

    |-- .cache

    |-- .pnpm

這裏有同學會問, pnpm 這樣能跑的起來嘛, 主倉庫庫依賴的其他包在哪裏。在這裏先給大家講解一下前置知識, 軟連接 和 硬鏈接的知識

還是有就是我的全局 store 我是如何去共享的?? 我在之前我先補充講解下 操作系統的硬鏈接 和 軟連接

ln 原文件 鏈接文件

硬鏈接,只能引用同一文件系統中的文件。它引用的是文件在文件系統中的物理索引(也稱爲 inode)。當移動或者刪除原始文件時,硬鏈接不會被破壞,因爲它所引用的是文件的物理數據而不是文件在件結構中的位置。硬鏈接記錄的是目標的 inode。

ls -s 原文件 連接文件

符號鏈接又叫軟鏈接,和原文件不是一個文件。例如 Windows 的快捷方式,如果原始文件被刪除,所有指向它的符號鏈接也就都被破壞了。符號鏈接記錄的是目標的 path。符號鏈接可以跨越文件系統,也可以爲目錄建立。軟鏈接有自己的 node,是 linux 特殊文件的一種,作爲一個文件,它的數據是它所連接的文件的路徑。

下面是我測試的文件

source 是源文件, soft  和 hard 分別 對應着  軟連接 和硬鏈接

我們先看文件大小

在文件大小方面  soft 鏈接 比 硬鏈接 更小  畢竟 他是 快捷方式

我們在看 源文件的 incode 以及對應的文件狀態

源文件對應的 link  是 2  對應的 Inode 是 xx

我們在通過 Inode 查出當前文件的 硬鏈接有多少個

看出來確實是 2 個。

軟硬鏈接 是 linux 中解決文件的共享使用問題的兩個方式,目的也是爲了節省磁盤空間。

我這裏先直接說結論:

pnpm 對於 項目的 依賴會 直接軟連接到 虛擬 store 下對應包的版本下, 然後虛擬 store 對應版本 會直接硬鏈接到 全局的 pnpm store 下

然後虛擬 store 包 依賴的其他版本 會互相之間軟連接。

大家直接看下張圖

比如我們項目中的 dependcies 依賴的 A 版本的 1.0.0  在 node_modules 其實是軟連接, 真實的文件其實在 虛擬 store 對應的 A

然後 A 在從全局的 store 做鏈接, 因爲 A 還依賴  C 這個包  C 是全局硬鏈接 然後 在 A 這個 node_modules 進行軟鏈接。

所以 pnpm 還是十分巧妙的。

實際操作一下

這是某個 pnpm 項目  我進入 node_modules

查看文件狀態

ls -ash

所有後面的依賴的都有一個箭頭 都是 .pnpm/xxx

說明都是軟連接到 虛擬 store 去了

值得關注的屬性有兩個,一個是 Links,表示硬鏈接個數,一個是 Inode

我們可以通過 Inode 去查詢所有的硬鏈接

find . -inum 8177610

可以看到,在全局 Library/pnpm/store / 下對應的文件目錄

4 條記錄 也對應了 links:4

總結

我們再去看下官網 pnpm 包管理器的特點

  1. 節省磁盤空間  這裏主要 涉及到 全局 store 和虛擬 store 概念的理解, 以及通過 操作系統的軟硬鏈接 來達到 節省磁盤空間的效果
  1. 提高安裝速度
  1. 基於符合鏈接的 node_modules 結構

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/7gwJZruwCbKwxqWlXvA3fQ