JavaScript 包管理的前世今生

發表於2017-08-04

npm / Yarn

和 Yarn 相比,npm 在快取、整合度和擴充套件性方面表現如何呢?我們將在這篇文章中一辨分曉。

如果將一個 JavaScript 開發者在 2005 年冰凍起來,然後在 2017 年的現在以某種神奇的方式將其解凍,那麼 JavaScript 包的爆炸式繁榮將會令他震驚。下方的視訊以一種炫酷的視覺展現方式向我們重現了這些包是如何隨著時間爆炸式繁榮起來的。
youtube視訊

從大型的框架庫,到解決某個問題的小型函式包,如今的 JavaScript 生態系統幾乎囊括了每一個需求所需要的包。JavaScript 作為一個強大而流行的程式語言,這種元件化的程式碼包對 JavaScript 的發展進化至關重要。隨著包的增多,開發者也看到了對於高效能、安裝管理包依賴的穩定的包管理器的需求。

我們這個系列的第一篇文章中,已經討論了 JavaScript 的革命,並介紹了現代前端開發中的三個核心部分:包管理器、應用打包和語言規範。本文會聊聊包管理器是如何出現、如何發展的,聊聊針對於可擴充套件應用,在未來包管理的革命道路上 Kenzan 為什麼推薦使用 Yarn 來作為包管理器。

包管理器橫空出世

隨著包管理器橫空出世,開發者放棄了下載包並手動引入所需檔案的原始方式,作為領先者的 npm(v2)和 Bower 開始嶄露頭角。

在那個時候,npm 只能處理 node 包。在 npm 早期的版本中,處理像 HTML 和 CSS 這樣的前端靜態資源還是比較罕見的。相反,Bower 就是專門為處理像 HTML、CSS 和 JS 這樣的前端靜態資源而誕生的。對於早期的前端專案 Bower 是一個極有價值的工具。Bower 擁有一套自己的前端包安裝源,並且提供了一個扁平化的依賴關係樹,在遇到衝突時,可以讓使用者來決定他們想要的版本。它為包管理功能開創了先河,並使 JavaScript 走向包繁榮的道路。

隨著應用的變重和依賴庫數目的增長,這個基礎開始崩潰。版本不匹配的問題越來越難處理。使用 Bower 構建需要 wiredep 和大量的配置。而且,最重要的問題是,CommonJS 和其他的模組規範並不能得到很好的支援。像 webpack™ 這樣的模組載入器曾經也很難處理 Bower 包合併和打包的格式,偶爾還會出現完全無法將它們模組化的情況。隨著模組化的 JavaScript 逐漸崛起,這成為了一個突出的問題。

針對這些問題,npm 釋出了 v3 版本。它提供了一個扁平化的依賴關係樹,擁有針對衝突的模組巢狀、CommonJS 模組支援、以及可以同時用於前端包和 node 包的單一生態系統等特性。總體來說,對於 npm ,這是一個巨大的成功,npm 被大量的應用於 JavaScript 社群。但是,這個系統很快就在專案中暴露出了缺陷。首先,npm v3 和 v4 在安裝包時的一致性並不確定,這就意味著模組並不總是以相同的順序或巢狀模式安裝。對於開發者來說,node 模組漂移會導致一些類似於“這個專案在我電腦上完全可以正常執行啊”之類的臭名昭著的 bug。第二個問題就是快取。npm 快取並不可靠,損壞的部分會被移除掉而不會被替代。這就意味著,開發者不能依賴當前的快取來作為之後的安裝,離線安裝是沒有問題的。

我們也看到像 JSPM 這樣的新的包管理器開始出現。JSPM(JavaScript Package Manager的縮寫) 是作為 SystemJS 的一個工具而出現的。這兩個軟體包試圖通過清理整合到軟體包管理來處理 JS 模組載入。JSPM 可以通過 npm 源、GitHub 和私有源來安裝依賴,然後更新 SystemJS 配置以對映到新模組,這樣便可以跨檔案匯入。儘管包管理和模組載入有一些共同的關注點,但它們似乎並沒有足夠同步,因此需要顯式地配對。另外,如果要同時使用這兩個工具來構建應用,配置是非常困難的。而且隨著 webpack 的流行普及,JSPM 開始失去支援。隨著 Angular CLI 用 webpack 替換 SystemJS,JSPM最終宣告失敗。

半路殺出個 Yarn

Yarn 在 2016 年年底由 Facebook 推出,是為了解決上述提到的一些 npm 的常見問題。Yarn 受 npm 的啟發,依賴巨大的 npm 源和 package.json 檔案,使得應用擴充套件具無痛的可重複性。在開發者使用同一版本 Yarn 的情況下,Yarn 使用一個自定義的鎖檔案(lockfile)和安裝演算法來確保安裝軟體包的一致性。這就保證了無論開發者選擇什麼樣的方式來安裝,都能夠擁有完全相同的 node 包。再也沒有軟體包漂移,再也沒有隱藏的 bug!這也意味著開發人員和 CI (持續整合)環境之間的一致性。

而且,針對 node 包,Yarn 提出了一種快取機制。使用暖快取(warm cache),Kenzan 的安裝速度有了 4 倍的提升。更快的安裝意味著更快的構建和更快的開發。快取也支援沙盒安裝和離線安裝。因為它可以防止在安裝期間注入任何惡意內容,所以這些特性對於企業級應用的重要性正在日益增加。因為軟體包會被快取和檢查,所以之後從快取中安裝包也是安全的。

在 Kenzan,相比於 npm,我們大量使用了 Yarn 為我們的客戶端應用進行構建,充分利用了 Yarn 構建的一致性、安裝時間短、沙盒安裝的相關特性。這些改變帶來的效果就是,我們 CI/CD(持續整合/持續交付)過程出現的問題更少了,安裝速度更快了。對於我們的客戶端應用而言,這意味著更少的資金投入、更少的不知所蹤的隱形的 bug。

但是這並不是說 Yarn 完美得沒有一點兒缺點。它確實存在著一些問題,比如對於私有 npm 包的支援有限,從 GitHub 上拉取軟體包也存在著一些問題。如果這些問題對於一個專案來說影響很重要,那麼 Yarn 可能並不是你的正確選擇。但是,相比於 npm,Yarn 社群的開發支援水平一直很高,通過 PR 提交的 bug 很快就能被修復。我們預期 Yarn 很快就能覆蓋 npm 的所有功能。

npm 重出江湖!

今年春天,npm 釋出了 v5 版本,這使得包管理器和 Yarn 的競爭更加激烈。這樣的話就出現了一個有趣的問題,對於那些已經選擇了 Yarn 作為構建工具的開發人員來說,是接著使用 Yarn 呢,還是放棄 Yarn 改用 npm 呢?

雖然沒有對比就沒有傷害,但是為了能夠做出明智的選擇,我們覺得有必要跑一些測試用例來做些研究。 npm v5 的確像他們說的那樣快嗎?和 Yarn 相比,npm 在快取、整合度和擴充套件性方面表現如何呢?

首先,我們先來測試下速度。我們使用 create-react-app 專案進行了安裝速度測試。我們比較了 npm v4、Yarn、npm v5,最後兩條資料是使用暖快取(warm cache)的情況。對於每一項,我們都跑了 10 次測試,以適應不同的網路條件。下面是我們的結果。

6ZqbjTpna1ddmzVgexCH8RP__M68He7nhjWKErPn

npm v5 確實很快,幾乎是 npm v4 的四倍!在冷安裝(cold install)的情況下甚至比 Yarn 還要快,但也只是快了一丟丟。在速度方面真正脫穎而出的是在暖快取(warm cache)情況下的 Yarn,比 npm 快了足足兩倍。這個測試的結論如下:是的,npm v5 與以前的版本相比確實表現出了強大的效能優勢,但與 Yarn 相比,快取安裝速度仍然略遜一籌。

接下來,我們來看看快取機制。上一個版本的 npm 存在著一個巨大的痛點:快取不一致。針對這一點,新版 npm 貌似已經解決了。npm 新版的快取是自我修復的,就是說,當損壞的資料被刪除時,它會自動重新安裝,並且安裝失敗時會重試。這意味著,新版 npm 可以做到快取安裝的一致性,這一點和 Yarn 類似。

在可用性和整合度方面,老版本 npm 曾經扯過後腿。新版本 npm 的 lockfile 檔案包含了所有包的確定性列表,其中將根級別包升級到樹的頂部,因此可以使用該檔案完成完整安裝。對於一致性安裝,Yarn 需要 yarn.lock 和 package.json。由於它們都是由 npm 團隊建立的,所以 npm 與私人軟體包源和軟體包釋出可以無縫整合。

最後,我們研究了擴充套件性。在這一點上,兩個包管理器在擴充套件大型企業應用時具有類似的功能。但是,Yarn 的初衷就是為了大型應用而設計的包管理器,併為此而持續發展的。它優先考慮了高階註冊功能的規模和安全性問題(儘管這些問題仍然在持續解決中)。Yarn 很可能會引領大規模應用改進的潮流。

我們該何去何從

這個系列的第一篇文章中,我們說過,所有的專案應該只使用一個包管理器。以我們的經驗,我們發現,使用工具保證跨機器的一致性有助於建立重用性好、bug 少的應用。但是至於你選擇哪個就應該考慮到你的團隊所開發專案的類別了。

隨著 npm v5 的釋出,npm 可能是一個好的選擇。對於小型專案,它提供了和 Yarn 幾乎相同的速度,跨機器也可以做到完全一致性。對於私有的 npm 包和 GitHub 倉庫,它的 bug 也更少,社群修復 bug、開發新特性也維持在一個充足的水平。在我們看來,它適用於規模較小、不太需要擴充套件的小型應用。

但是,在 Kenzan,我們關注的是具有最大限度可擴充套件性的大型企業應用。考慮到這些限制,Yarn 已經被證明是個明智的選擇。它給我們提供了快速構建的速度、依賴包的一致性,社群改進特性、開發新特性也很活躍。無論一個應用有多少開發者,無論處於什麼環境下,只要使用 Yarn,我們就能保證可擴充套件性。正是因為這些原因,我們選擇 Yarn 作為我們唯一的包管理器,同時我們也推薦你嘗試一下。

請繼續關注我們的下一篇部落格文章,我們將通過探索打包模組的工具,將我們的前端技術棧進一步擴充套件。

譯者注:以下是原作者對自己所在公司的介紹,譯文保留。

Kenzan 是一家軟體工程和全面服務諮詢公司,提供通過數字化轉換來驅動的定製的端到端解決方案。Kenzan 結合領導力與技術專長,與合作伙伴和客戶展開合作,利用前沿技術,提供從理念到開發到交付的完整的解決方案。Kenzan 是一家技術驅動公司,專業從事應用和平臺開發、架構諮詢和數字化轉換。

webpack 是 JS Foundation 的商標。

相關文章