[pnpm] pnpm 與 npm/yarn 的對比

来源:https://www.cnblogs.com/feixianxing/p/18359597/node-package-manager-compare-pnpm-vs-npm-and-yarn
-Advertisement-
Play Games

本文比較了NPM、Yarn 和 pnpm 三種包管理工具的特點,重點分析了它們在安裝速度、依賴管理、磁碟空間使用、依賴衝突處理等方面的差異,重點介紹了pnpm的依賴組織結構。 ...


JavaScript 應用程式通常依賴於許多外部庫,這些依賴項通常通過包管理器來管理。預設情況下,Node.js 使用 NPM 作為包管理器。

由於早期的 NPM 存在各種不足,社區後來開發了 Yarn 和 pnpm 作為替代品。

如果要使用 Yarn 和 pnpm,則需要先通過 NPM 進行安裝。

早期 NPM 的不足

image-20240814145147621

  1. 依賴樹過深

    在 NPM 3.0 之前,NPM 使用了嵌套依賴樹的結構。這意味著如果一個項目的多個依賴項需要同一個包的不同版本,NPM 會在每個依賴項的目錄中重覆安裝該包。這種結構會導致 node_modules 目錄非常深,特別是在 Windows 系統中,這可能導致路徑長度限制的問題。

  2. 重覆安裝和磁碟空間浪費

    每次安裝包時都會重新從頭開始解決依賴關係,並逐個下載和安裝包。即使是已經安裝過的包,也可能會再次下載,而沒有利用緩存機制。這種重覆安裝的策略會導致安裝十分緩慢。

  3. 依賴版本不確定

    在早期版本的 NPM 中,沒有類似 yarn.lockpackage-lock.json 這樣的鎖文件。這意味著即使 package.json 中指定了版本範圍(例如^1.0.0這種表示可以接受一個範圍的版本),依賴關係的解析和安裝仍然是動態的,可能會因為時間或網路狀態的不同而導致不同的版本被安裝。

  4. 扁平化依賴樹

    NPM 在 3.0 版本引入了扁平化依賴樹,以解決早期版本中嵌套依賴樹帶來的問題,但是扁平化依賴帶來了新的問題。

    • 依賴衝突:扁平化依賴樹的設計將所有依賴項都安裝在項目的根 node_modules 目錄中,這意味著多個包可能會共用同一個依賴項的版本。如果不同的包需要不同版本的相同依賴項,就可能會發生衝突。
    • 幽靈依賴:依賴的依賴被平鋪在根node_modules目錄中,這意味著即使應用的package.json中沒有聲明的依賴,也可以被引入並使用。這種現象會導致依賴關係和依賴版本的不明確。

    image-20240814151136457

    圖中的虛線就代表幽靈依賴,也叫隱式依賴

    依賴 E 原本是 B 的依賴,但是被扁平化後提升到 node_modules 頂層。

    這個 E 沒有被顯式地在 package.json 中聲明,但是結合 node.js 的模塊解析機制可知這個依賴是可以被 Project 引入的。

    這種 意料之外 的依賴關係會使得項目難以維護。

Yarn

Yarn的提出是為瞭解決 NPM 的不足,它具有以下特點:

  1. 確定性安裝

    Yarn 引入了 yarn.lock鎖文件,明確了依賴的版本。

  2. 更快更小

    Yarn 通過並行下載以及引入緩存機制來加快安裝速度,並且由於緩存的存在,在離線狀態下也可以安裝已緩存過的依賴。

  3. 扁平化依賴結構

    減少了路徑深度,提高了依賴解析的速度。解決了依賴衝突問題:Yarn 會通過將不同版本的依賴項放在各自子目錄的 node_modules 中來解決衝突,而不是強制將所有依賴都安裝在頂層。

    image-20240814151859723

  4. 可以通過配置 workspaces 支持 monorepo。

不足

  • 沒有解決幽靈依賴的問題;
  • workspaces 配置較繁瑣。

pnpm

image-20240814142111601

pnpm的特點:

  1. 節省磁碟空間

    npm 和 Yarn 會在每個項目的 node_modules 目錄中為所有依賴項存儲完整的文件副本。如果有多個項目依賴相同的包,那麼這些包會被重覆存儲

    pnpm 使用中心化的 store 統一存儲安裝的包,項目內的依賴通過鏈接指向 store 中的依賴。如果有多個項目依賴相同的包,都指向 store 中單一的包。

  2. 安裝速度更快

    pnpm npm/yarn/...
    1. 依賴解析。 倉庫中沒有的依賴都被識別並獲取到倉庫。
    2. 目錄結構計算。 node_modules 目錄結構是根據依賴計算出來的。
    3. 鏈接依賴項。 所有以前安裝過的依賴項都會直接從倉庫中獲取並鏈接到 node_modules
    1. 解析所有依賴。
    2. 獲取所有依賴。
    3. 將所有依賴寫入node_modules
    pnpm 安裝過程的插圖。 所有的包會儘快解吸、獲取和硬鏈接。 一個 Yarn Classic 或 npm 這樣的包管理器如何安裝依賴項的示意圖。

    pnpm 的中心化store可以更大程度地復用依賴包,使得安裝依賴這一步驟更快完成。

  3. 支持 monorepo,配置比起 yarn 來說相對簡單,並且得益於 pnpm 的特性,安裝依賴很快。

  4. 非扁平化的 node_modules

    上文說到 yarn 和 npm 為瞭解決路徑過長、依賴管理複雜等問題,將依賴進行扁平化管理。但是也帶來了幽靈依賴等新問題。

    pnpm 的創新點在於提出了 基於符號鏈接的非扁平化 node_modules 結構,解決了幽靈依賴問題。

    硬鏈接和軟鏈接

    在 Linux 操作系統中,每一個文件對應一個 inode(索引節點)。鏈接是一種在共用文件和訪問它的用戶的若幹目錄項之間建立聯繫的一種方法。

    image-20240814164425085
    • 硬鏈接是文件的別名,和源文件指向同一個 inode。即硬鏈接和源文件是同一個文件
    • 軟連接也叫符號鏈接,是一種特殊的文件類型,其中包含對另一個文件的引用。軟鏈接可以看作是對一個文件的間接指針,類似於 Windows 操作系統下的 快捷方式即軟鏈接和源文件是不同文件

    在 Windows 中也有軟硬鏈接的概念,在 cmd 中通過 mklink指令創建鏈接:

    • 硬鏈接:

      mklink /H link_name target_file
      
    • 軟鏈接

      mklink link_name target_file
      

    pnpm的node_modules結構

    文件結構示例:comparing-node-modules/pnpm5-example at master · zkochan/comparing-node-modules (github.com)

    pnpm將實際的依賴文件都安裝到全局store中,在項目中的node_modules文件夾內通過創建鏈接來使用store中的依賴。

    與 yarn 和 npm 直接將所有依賴平鋪在 node_modules 中的做法不同,pnpm 在 node_modules 中創建了一個 .pnpm文件夾,再將所有依賴都平鋪在這個文件夾中。這樣 node.js 的模塊解析演算法就無法引入非頂層依賴了,故解決了幽靈依賴問題。

    .pnpm 中的依賴通過軟鏈接建立依賴之間的父子關係,並通過硬鏈接指向實際存在於全局store中的依賴包。

    在 package.json 中顯式聲明的依賴會通過軟鏈接提升到 node_modules 文件夾下,因此 node.js 可以正常解析 package.json 中聲明的依賴。

    .pnpm 中,依賴通過.pnpm/<name>@<version>/node_modules/<name>的形式進行記錄,可以看到同一個包的不同版本會被分開記錄

    image-20240814181732826

    如上圖,項目中只有 express 這一個依賴,而 express 有許多子依賴,這裡只列舉了 qs 這一個依賴。

    可以觀察到,這種基於鏈接的 node_modules 結構實現了:

    1. 項目的 node_modules 只能解析到 package.json 中顯式聲明的依賴,解決了幽靈依賴問題
    2. 所有依賴都被平鋪在 .pnpm 文件夾中,不會導致過長的文件路徑
    3. 實際的依賴被安裝在全局的store中,項目中僅通過硬鏈接進行關聯,節省了磁碟空間
    4. 觀察到express和它的依賴同屬於一個文件夾層級(圖中藍色區域),express 所有的依賴都軟鏈至了 node_modules/.pnpm/ 中的對應目錄。 把 express 的依賴放置在同一級別避免了迴圈的軟鏈。

現在的 NPM

yarn 和 pnpm 屬於社區產物,NPM 作為官方的包管理器,一直在吸收社區好物的優點。

現在的 NPM 也有了鎖文件來明確依賴的版本,並且也通過使用緩存、改進依賴解析演算法等手段加速了安裝。

NPM 在 7.0 版本之後也支持配置 monorepo 了,可以在 package.json 中直接配置,但是只支持一些簡單的功能。yarn 則提供了插件系統。

總結

特點 NPM Yarn pnpm
安裝速度 較慢 較快 大部分情況下比 Yarn 塊
依賴管理 直接安裝到 node_modules 通過緩存加速安裝 中心化 store,依賴通過符號鏈接安裝
磁碟空間使用 中等 最低,通過去重和鏈接機制
依賴衝突處理 容易出現衝突 通過鎖文件和解析依賴減少衝突 嚴格隔離各依賴版本,減少衝突
鎖文件 package-lock.json yarn.lock pnpm-lock.yaml
幽靈依賴問題 可能發生 可能發生 嚴格依賴樹,避免幽靈依賴
monorepo支持 基礎支持 功能豐富,包含插件系統 高效的工作空間管理,模塊共用更優化
安裝一致性 可能由於緩存和平臺差異而不一致 高,一致性較好 更高,通過全局硬鏈接機制確保一致性

性能對比圖像來自 pnpm 官方文檔:Benchmarks of JavaScript Package Managers | pnpm中文文檔 | pnpm中文網

Graph of the alotta-files results


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • title: 使用 onNuxtReady 進行非同步初始化 date: 2024/8/16 updated: 2024/8/16 author: cmdragon excerpt: 摘要:本文詳細介紹了Nuxt.js框架中的onNuxtReady函數用途、使用場景及其實現步驟,並通過集成分析庫的示例 ...
  • 在做項目的時候,Web端需要適配移動端,且部分參數需要判斷對應系統或瀏覽器。 在IOS中,因為高版本的系統Safari瀏覽器採用了Mac的內核,所以導致普通的判斷無法識別到對應系統。(userAgent.match(/(Macintosh)/) && navigator.maxTouchPoints ...
  • Mall-Vue —— 一個基於 VUE + VUEX + iView 做的一個電商網站前端項目。這個項目是一個純前端項目,實現了首頁、商品頁面、購物車等大部分常用的電商網站頁面功能。 ...
  • 本文介紹了記憶體管理的基礎知識,重點分析了棧區與堆區的區別,並詳細討論了V8引擎的記憶體管理機制,包括垃圾回收策略和優化技術。文章通過實例代碼展示了堆區和棧區的記憶體變化,並探討了v8如何通過並行、增量和併發技術優化垃圾回收性能。 ...
  • 本文主要內容: screenX 和 screenY, clientX 和 clientY / x 和 y pageX 和 pageY layerX 和 layerY 在處理滑鼠事件(MouseEvent)時,瞭解不同的坐標系是非常重要的。常見的坐標系包括屏幕坐標(screen)、客戶端坐標(clie ...
  • 一、載入問題 用高德地圖做了個進京證路線規劃的功能,官網也是有 React 代碼示例。但是吧,這個Demo有問題,地圖是能載入成功,但是其他功能再用 map 這個變數肯定不行,果不其然是null,處理也簡單,把公共變數都管理起來就行了。 const [map, setMap] = useState( ...
  • title: 使用 onBeforeRouteUpdate 組合式函數提升應用的用戶體驗 date: 2024/8/15 updated: 2024/8/15 author: cmdragon excerpt: 摘要:本文介紹如何在Nuxt 3開發中使用onBeforeRouteUpdate組合式函 ...
  • 歐陽堅持每周更新一篇高質量文章半年後的收益:收入1380.27元、電子書一本、微信技術群418人、微信好友459人、文章38篇 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...