[譯] Yarn - Javascript 新一代套件管理

本文轉譯並補充自 - Yarn: A new package manager for JavaScript

在 Javascript 社群中,開發者們分享成千上萬的原始碼讓我們可以省去重造輪子的時間,不用重新打造函式庫,框架,元件等。
而每段原始碼都有可能相依於其他原始碼片段,這些相依的程式碼通常會透過套件管理(package manager)來管理。
其中在 Javascript 裡,最熱門的就屬 npm ,在上面有 5 百萬個開發者,套件庫提供了超過 300,000 模組,更驚人的是每個月有超過 5 億次的下載量。

Facebook 的團隊使用 npm 客戶端工具已經好幾年了,隨著原始碼大幅的成長,我們開始遭遇到一些問題包含了一致性,安全性,效能方面。
在嘗試解決遇到的每一個問題之後,我們開始創造一套新的、更可靠的解決方案來協助我們管理相依性的問題。

這東西叫做 Yarn - 一個快速,可靠,更安全取代 npm 客戶端的工具。

我們很開心的發佈釋出 Yarn 為開放原始碼專案,並和 Exponent, Google, Tilde 協作。使用 Yarn ,開發者仍然存取 npm 套件庫 (npm registry),但可以更快速的安裝和管理套件,保持套件的一致性,可靠的離線環境的安全性
Yarn 讓開發者在使用這些分享的開源碼時可以自信的更新,替換,因此開發者們可以專注在他們的任務 - 開發產品和功能。

npm registry 收錄開發者提供模組的檔案庫與其對應資訊列表,翻譯為註冊表,但譯者認為套件庫較能表達其意義。

Facebook 管理 Javascript 模組的演化

在使用套件管理之前,常見的狀況就是 Javascript 開發者直接透過 CDN 存取相依的片段原始碼。第一版的 npm 在 Nodejs 出現之後很快的就被開發出來,很快的它就成為世界上最熱門的套件管理工具。創造了數以千計的新開源專案以及比以往更多的開發者分享他們的成果。

Facebook 的許多專案像是 React,也相依於 npm 上面的程式碼。然而當我們內部成員增加的時候,當不同的成員與機器要安裝這些相依模組就開始面臨到一致性的問題,大量的時間花在處理安裝相依模組。同時由於 npm 會自動執行一些相依的程式碼而伴隨著安全性的議題。於是我們嘗試開發一個解決方案去處理這些問題。

嘗試擴展 npm 客戶端工具(npm client)

起初,跟著官方的最佳實踐,我們只檢查 package.json 然後要求開發者手動執行 npm install。這對開發者來說運作還算良好,不過卻在我們持續整合環境(continuous integration environments)中出現問題,因為該環境處於沙箱模式,並且基於安全性的因素不與外部網路連接。

接著我們的解決方案則是檢查所有的 node_modules 然後存到檔案庫裡套件庫(registry)。雖然它能運作,但同時讓一些簡單的操作變得非常困難。舉例來說更新次版號的 babel 會產生高達 800,000 行的 commit 導致完整下載,執行 lint 規則檢查像是不符合規範的 utf8 字節序列,windows 行結尾,非 png 壓縮圖片,等等等這些任務變得很難完成。合併 node_modules 的修改很可能就耗掉開發者一整天。

我們的版本控制團隊也指出那些我們 check-in 的 node_modules 目錄包含了太大量的 metadata。例如:React Native 的 package.json 現在就有 68 個相依的模組,然後在執行 npm install 之後 node_modules 目錄包含了 121,358 個檔案。

我們做了最後的嘗試 - 補強 npm client,使其適用於 Facebook 的工程師。協助處理那些我們需要安裝的大量程式碼。
我們決定 zip 打包整個 node_modules 目錄,然後上傳到內部的 CDN,之後開發者和持續整合環境都可以下載一樣的檔案。
這讓我們可以從版本控制中移除數以千計的檔案,不過為了達到這個功能開發者提取和建置時需要內部的存取權限。

另外,我們在處理問題的時候也會需要使用 shrinkwrap 的功能,這讓我們可以鎖定特定相依套件的版本。預設 shrinkwrap 並不會產出,因此如果工程師忘記下指令的話那麼版本又會不一致,所以我們寫了一個工具用來驗證 shrinkwrap 的檔案內容是否符合 node_modules。

這些檔案是超大的 JSON blob 並且 keys 沒有排序,因此要修改它們勢必會產生大量的輸出,然後難以審核 commit。
為了解決這個問題我們需要加入額外的 script 來排序它們。

最後,使用某些版本的 npm 更新單一的相依套件可能會連帶更新一些不相關的檔案。這將導致每一次更新比預期的更大,而且必須將其納入整個提交 node_modules 或更新到 CDN 的流程,這不是開發者樂於見到的狀況。

開發新的客戶端工具(client)

比起持續補強 npm 客戶端工具,我們選擇嘗試更全面的看待這些問題。假如我們開發一個全新的客戶端工具能夠完全解決我們曾遭遇過的這些問題呢?倫敦辦公室的 Sebastian McKenzie 開始嘗試挑戰這個點子,這點子的潛力讓我們很興奮。

一開始,我們開始詢問業界的開發者們,發現他們都面臨一系列類似的問題,嘗試使用類似的解決方案,一次解決一個遭遇的問題。
很明顯的社群正面臨通過合作來解決這一系列的問題,而我們可以開發出一個方案適用於任何人。
得到 Exponent, Google, Tilde 工程師的協助,我們開發出了 Yarn 並在各個主流的 JS 框架中測試與驗證其效能,還包括了 Facebook 以外開發團隊的使用情境。今天(2016-10-11)我們很開心與社群分享這個成果。

Yarn 介紹

Yarn 是一個新的套件管理工具,主要用來取代既有的工作流程中 npm client 或其他套件管理工具的部分(安裝、更新、移除套件等的指令集),同時兼容於現有的 npm registry。大部分的功能與操作與既有的流程相同並且更快速,安全,可靠。

任何套件管理工具的主要功能是安裝模組套件 - 一個特定用途的片段程式碼 – 從全球通用的套件庫(registry)中安裝到開發者本地的環境中。每一個套件可能會相依於其他套件。一個典型的專案可能具備數十,數百甚至上千個相依的模組。

這些相依的模組都有版號並且基於語意化版本規範(semver)安裝或更新。語意化版本規範了版號的意義與相關符號的規則,這些規則可以讓我們知道該版本是否相容於上個版本,是屬於加入新功能,或者只是修復 Bug,然後基於這些規則來確認是否能更新或該更新到什麼版號。

然而語意化版本規範(semver)需要仰賴套件開發者不犯任何錯誤 - 如果沒有鎖定相依套件的版本,新的 Bug 或錯誤的修改極有可能就被安裝了。

架構

在 Node 的生態圈裡,相依的模組會被放在專案下的 node_modules 目錄。然而隨著合併重複模組的狀況,這個檔案結構可能不同於真實的目錄結構

譯者補充:npm 顯示的相依階層跟實際目錄結構不同。

npm 客戶端工具安裝相依模組到 node_modules 目錄並不會依據模組結構(不確定性)。意味著它只會依序安裝模組,而 node_modules 目錄中的結構每一個人可能是不一樣的。這些差異可能最造成『我可以跑啊』的狀況,通常需要很長的時間去找問題點。

Yarn 透過 lockfiles(yarn.lock) 鎖定機制和一套安裝邏輯解決了這些關於版本和不確定性的問題使其具備可靠性與確定性。這些 lockfiles 會鎖定安裝的相依模組為特定版本,確保安裝在每台機器上的 node_modules 結果是一致的。lockfile 使用精準的格式撰寫與排序的鍵 (keys)來確保修改動作最小化,同時在審核的時候比較單純。

整個安裝流程拆解為下面三個步驟:

  1. 辨識:Yarn 透過發送請求到套件庫(registry)開始解析相依的套件模組,然後層層遞迴的檢查每一個模組相依的東西。
  2. 擷取:下一步,Yarn 檢查全域快取的目錄(global cache directory)看看是否有需要的套件已經被下載了。如果沒有,Yarn 開始下載模組的壓縮包(tarball)並將其存放到全域快取的目錄下,所以這表示我們是可以離線工作的,同樣的模組不需要下載兩次。您也可以將相依的模組使用壓縮檔的形式加入版控來達到完全離線安裝。
  3. 連結:最後,Yarn 從全域快取(global cache)複製所需的檔案到本地的 node_modules 完成整個流程。

因為清楚的分拆這些步驟並確保一致的結果,Yarn 便有能力平行處理每個操作,讓整個安裝流程更快速。
在某些 Facebook 專案 ,Yarn 簡化了整個安裝流程,從幾分鐘到只剩幾秒鐘。Yarn 也提供互斥的機制確保多個執行的指令不會互相干擾。

Yarn 會嚴格把關整個安裝流程,協助您掌控安裝流程。套件的檢核資訊會存放在 lockfiles(yarn.lock )確保每一次安裝的都是一樣的套件模組。

功能

除了確保安裝流程更迅速和可靠,Yarn 也支援其他功能讓我們更方便的管理相依套件,簡化工作流程。

  • 與 npm 和 bower 相容,同時也支援不同的套件庫(registry)
  • 嚴格限制安裝套件的 Licenses 和輸出相關訊息
  • 提供 API 協助建置工具取得輸出一些工具的資訊(譯者註:此部分尚未完成,更多資訊參考此 Issue
  • 精簡有意義且美觀的指令輸出資訊

使用 Yarn 於正式環境

在 Facebook 我們已經在正式產品中使用 Yarn,同時其運作非常良好。使得許多專案在管理相依套件上更加方便。
我們讓工程師即便在每次的移動中都能夠快速的離線建置,加速整個工作流程。

您可以看到 Yarn 和 npm 安裝 React Native 的時間差距,具體資料您可以查閱這裡

入門

最快速的入手方式就是執行

1
2
3
4
$ npm install -g yarn
$ yarn

# 又或者參考官方文件:https://yarnpkg.com/en/docs/install

yarn 就可以在工作流程中透過相同或相似的指令取代 npm

  • npm install -> yarn

此指令不需任何參數,yarn 會讀取 package.json 然後從 npm registry 擷取套件並安裝到 node_modules。等同時使用 npm install

  • npm install --save <name> -> yarn add <name>

我們移除 npm 預設不紀錄模組並把 --save 拆開為參數的行為。執行 yarn add <name> 等於 npm install --save <name>

發展

許多人和我們一起建造了 Yarn 來解決常見的問題,我們意識到 Yarn 需要成為一個社群專案讓更多人使用。Yarn 現在已經釋出可以在Github上找到,我們為 Node 社群貢獻最棒的東西就是:使用 Yarn,分享一些點子,撰寫文件,互相支援。我們相信 Yarn 有了一個好的開始,但有了您的幫助它會變得更好。

相關閱讀

作者

andyyou(YOU,ZONGYAN)

發表於

2016-10-12

更新於

2023-12-05

許可協議