跳至主要內容

架構

一般架構

Yarn 透過核心套件(發布為 @yarnpkg/core)運作,公開構成專案的各種基本元件。某些元件是您可能從 API 中辨識的類別:ConfigurationProjectWorkspaceCacheManifest 等。這些都是由核心套件提供的。

核心本身並未執行太多動作,它僅包含管理專案所需的邏輯。為了從命令列使用此邏輯,Yarn 提供了一個稱為 @yarnpkg/cli 的間接指令,有趣的是,它也未執行太多動作。然而,它具有兩個非常重要的職責:根據目前目錄 (cwd) 注入專案執行個體,並將預先建置的 Yarn 外掛程式注入環境。

Yarn 以模組化方式建置,允許與第三方互動相關的大部分商業邏輯外化到其自己的套件中,例如 npm 解析器 只是眾多外掛程式之一。此設計讓我們能使用更簡單的程式碼庫 (因此能提升開發速度和穩定產品),並讓外掛程式作者能夠撰寫自己的外部邏輯,而無需修改 Yarn 程式碼庫本身。

安裝架構

執行 yarn install 時會發生什麼事,可以用幾個不同的步驟來總結

  1. 首先,我們會進入「解析步驟」

    • 首先,我們會載入儲存在鎖定檔中的項目,然後根據這些資料和專案的目前狀態 (它會透過讀取明細檔,也就是 package.json 來找出),核心會執行內部演算法來找出哪些項目遺失。

    • 對於每個遺失的項目,它會使用 Resolver 介面查詢外掛程式,並詢問它們是否知道符合給定描述符 (supportsDescriptor) 及其確切身分 (getCandidates) 和遞移相依性清單 (resolve) 的套件。

    • 取得新的套件資訊清單後,核心會針對新加入套件的傳遞依賴項開始新的解析傳遞。這會重複執行,直到它找出依賴項樹中的所有套件現在都將其資訊儲存在鎖定檔中。

    • 最後,一旦依賴項樹中的每個套件範圍都已解析為資訊,核心會在記憶體中最後一次建構樹,以產生我們稱為「虛擬套件」的內容。簡而言之,這些虛擬套件是同一個基礎套件的分離實例 - 我們使用它們來區分所有列出對等依賴項的套件,其依賴項集會根據它們在依賴項樹中的位置而改變(請參閱此詞彙表條目以取得更多資訊)。

  2. 解析完成後,我們進入「擷取步驟」

    • 現在我們有了構成依賴項樹的精確套件組,我們會逐一反覆執行,並針對每個套件向快取發出新的請求,以了解是否可以在任何地方找到該套件。如果找不到,我們會像前一步驟一樣,詢問我們的外掛程式(透過Fetcher介面)是否知道該套件(supports),如果是,則從其遠端位置擷取(fetch)。

    • 關於擷取器的有趣小知識:它們透過fs上的抽象層與核心通訊。我們這樣做,以便我們的套件可以來自許多不同的來源 - 它可以來自從登錄下載的套件的 zip 檔案,或來自portal:依賴項的磁碟上的實際目錄。

  3. 最後,一旦所有套件都準備好使用,就會進入「連結步驟」

    • 為了正常運作,您使用的套件必須以某種方式安裝在磁碟上。例如,在原生 Node 應用程式的案例中,您的套件必須安裝到一組 node_modules 目錄中,才能讓詮譯器找到它們。這就是連結器的作用。透過 LinkerInstaller 介面,Yarn 核心會與已註冊的套件進行通訊,讓它們知道相依性樹狀結構中列出的套件,並說明它們的關係(例如,它會告訴它們 tapablewebpack 的相依性)。然後,套件可以自行決定如何處理這些資訊。

    • 這樣做表示可以很輕鬆地為其他程式語言建立新的連結器 - 您只需要針對 Yarn 提供的套件撰寫您自己的邏輯,說明應該發生什麼事。想要產生 __autoload.php 嗎?去做吧!想要設定 Python 虛擬環境嗎?沒問題!

    • 另一個很酷的地方是,相依性樹狀結構中的套件不必全部都是同種類型的。我們的套件設計允許同時實例化多個連結器。更好的是 - 套件可以跨連結器互相相依!您可以有一個 JavaScript 套件相依於 Python 套件(例如,技術上來說 node-gyp 就是這樣)。