一文帶你深度理解 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 這樣能跑的起來嘛, 主倉庫庫依賴的其他包在哪裏。在這裏先給大家講解一下前置知識, 軟連接 和 硬鏈接的知識
soft link 和 hard link
還是有就是我的全局 store 我是如何去共享的?? 我在之前我先補充講解下 操作系統的硬鏈接 和 軟連接
硬鏈接(hard link )
ln 原文件 鏈接文件
硬鏈接,只能引用同一文件系統中的文件。它引用的是文件在文件系統中的物理索引(也稱爲 inode)。當移動或者刪除原始文件時,硬鏈接不會被破壞,因爲它所引用的是文件的物理數據而不是文件在件結構中的位置。硬鏈接記錄的是目標的 inode。
軟鏈接(soft link)
ls -s 原文件 連接文件
符號鏈接又叫軟鏈接,和原文件不是一個文件。例如 Windows 的快捷方式,如果原始文件被刪除,所有指向它的符號鏈接也就都被破壞了。符號鏈接記錄的是目標的 path。符號鏈接可以跨越文件系統,也可以爲目錄建立。軟鏈接有自己的 node,是 linux 特殊文件的一種,作爲一個文件,它的數據是它所連接的文件的路徑。
下面是我測試的文件
source 是源文件, soft 和 hard 分別 對應着 軟連接 和硬鏈接
我們先看文件大小
在文件大小方面 soft 鏈接 比 硬鏈接 更小 畢竟 他是 快捷方式
我們在看 源文件的 incode 以及對應的文件狀態
源文件對應的 link 是 2 對應的 Inode 是 xx
我們在通過 Inode 查出當前文件的 硬鏈接有多少個
看出來確實是 2 個。
軟硬鏈接 是 linux 中解決文件的共享使用問題的兩個方式,目的也是爲了節省磁盤空間。
pnpm 如何 link 的
我這裏先直接說結論:
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 包管理器的特點
- 節省磁盤空間 這裏主要 涉及到 全局 store 和虛擬 store 概念的理解, 以及通過 操作系統的軟硬鏈接 來達到 節省磁盤空間的效果
-
pnpm 安裝依賴時,依賴會被存儲在硬盤中,不同項目的同一依賴都會硬鏈接到硬盤位置,不會額外佔用磁盤空間。
-
同一依賴包的不同版本,也只會將不同版本中有差異的文件添加到倉庫中,不會下載整個包占用磁盤空間。
- 提高安裝速度
-
安裝依賴時,會先去硬盤位置尋找包,如果能找到,則建立硬鏈接,比起重新下載包或者從緩存中拷貝移動包,速度快了很多
-
pnpm insatll 分 3 個階段執行安裝 依賴解析, 目錄結構計算 鏈接依賴項, 所有以前安裝過的依賴項會直接從全局 store 連接到 node_modules 中
- 基於符合鏈接的 node_modules 結構
-
這種佈局的一大好處是隻有真正在依賴項中的包才能訪問。使用平鋪的
node_modules
結構,所有被提升的包都可以訪問,避免了幽靈依賴問題 -
避免了 NPM 分身問題。NPM 分身(NPM doppelgangers)則指的是對於相同依賴的不同版本,由於
hoist
的機制,只會提升一個,其他版本則可能會被重複安裝
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/7gwJZruwCbKwxqWlXvA3fQ