爲何咱們從Yarn切換到pnpm

logo.png

原文網址: https://www.takeshape.io/arti...

原文做者:ANDREW SPROUSE前端

這是一個重大的決定node

在 TakeShape,咱們很是關注開發人員的生產力。 咱們是一個資源有限的小型團隊,所以值得花時間考慮如何更快,更高效地合做。 在最近重構咱們的構建過程時,咱們作出了一個重大決定:咱們將拋棄 Yarn 並改用 pnpm 來管理咱們的依賴項並運行咱們的腳本。 這是關於咱們如何作出該決定以及迄今爲止如何使咱們受益的故事。npm

pnpm.png

最初,TakeShape 的代碼庫分散在多個Git存儲庫中。 每一個軟件包都是獨立開發的,而且彼此依賴。 從理論上講,這是理想的設置。 在實踐中,咱們發現全部東西都是相互依賴的,咱們真的但願可以同時測試和發佈全部軟件包。 當咱們爲其中一個軟件包發行新版本時會遇到失敗,可是會忘記在依賴它的其餘項目中更新該版本。json

最終,咱們意識到,在保持項目的分離性和依賴性時,monorepo 是正確的權衡。 咱們全部的軟件包(如Web客戶端,前端路由庫和CLI)都存在一個可測試且可部署的單元中。 咱們的包可使用package.json 中的 link :語法相互依賴。架構

這在很大程度上是有效的,可是咱們仍然發現管理咱們的 monorepo 的部分是乏味的。這在必定程度上是由於咱們的 monorepo 中的每一個包都用本身的包管理器管理本身的依賴關係,json和它本身的lock 文件。即便每一個包使用相同的開發工具鏈,如eslint、Jest、Typescript和Babel,每一個包單獨聲明這些 devdependency ,這個工具鏈必須在咱們全部的包中保持最新。咱們決定不使用Yarn的工做區特性來解決這個問題,由於這將須要拋棄每一個包的lock文件,而使用單個工做區範圍的lock文件。工具

避免幻像依賴也比實際須要更加棘手。 當您的代碼導入未在 package.json 中聲明的包時,就會產生幻像依賴。 假設您將 Package A 添加到依賴於 Package B 的項目中。因爲 Yarn 將全部程序包都保留在 node_modules 的根目錄下,所以您能夠導入和使用 Package B ,而無需將其徹底放在 package.json 中。 儘管不是很常見,但這是一個錯誤的作法,它確實會減慢調試過程的速度,除非您記得有意地檢查它。開發工具

咱們的 monorepo 也使咱們的CI管道比所需的更加複雜。 首先,咱們並行化了 CircleCI 構建,以加快慢速 Webpack 構建。 可是,隨着咱們的 monorepo 的增加,爲每一個構建分別安裝依賴項的開銷也在增長。 爲每一個構建安裝依賴項成爲瓶頸。 做爲迴應,咱們使用本身編寫和維護的 CircleCI 腳本鞏固了構建過程,以減小使用工做。最終,咱們獲得了一組脆弱的CI腳原本對任何包進行剪裁、測試和構建更改。測試

2.png

咱們真正須要的是一種遞歸安裝軟件包,提高全部共享依賴關係並運行腳本以進行lint,測試和構建的方法。 咱們知道Yarn並不能爲咱們擴展,所以咱們開始考慮替代方案:spa

  • 若是咱們保留Yarn並添加Lerna怎麼辦? 添加Lerna能夠解決CI腳本編寫中的一些問題,但不能解決幻像依賴項或重複的devDependencies帶來的問題。
  • 若是咱們添加了Lerna並使用了Yarn Workspaces,該怎麼辦? 工做區將解決共享開發人員依賴關係並自動連接依賴關係的問題。 可是將全部node_modules提高到項目根目錄只會加重幻想依賴項的風險,並致使某些模塊和工具出現問題。
  • 若是咱們升級到Yarn 2.0並使用……其餘……該怎麼辦? Yarn 2.0確實使人興奮。 它具備不少很酷的功能,包括 Plug'n'Play(PnP)。 PnP能夠解決幻想依賴項的問題,可是它可能與某些須要文件訪問的依賴項不兼容。 Yarn 2.0與Lerna不兼容; 相反,它具備插件架構。 這些插件有可能解決咱們對CI腳本的需求,但它們還不夠成熟,沒法自信地用於生產中。
  • 若是咱們用pnpm替換Yarn怎麼辦? 根據 pnpm 的說法,它存在「 [使用]硬連接和符號連接僅一次在磁盤上保存模塊的一個版本」。 這種組織 node_modules 的方法能夠防止幻象依賴並避免在吊裝時出現其餘問題。 它能夠解決與Yarn 2.0的PnP相同的問題,可是因爲它僅使用連接,所以具備更普遍的兼容性。 pnpm還包含與Lerna相似的過濾功能。

最後,pnpm對咱們來講最有意義。 咱們發現pnpm的遞歸命令和--filter標誌消除了咱們對像Lerna這樣的單獨軟件包的須要。 將Babel,ESLint和Jest之類的共享開發人員依賴項無縫移動到咱們項目的頂層,如今能夠從單個共享源更新這些軟件包。 在切換過程當中,咱們甚至在咱們的項目中發現並修復了多個幻象依賴項!插件

採用pnpm後,咱們複雜的CircleCI管道被簡化爲一個做業。結果,咱們將整個可計費的CircleCI分鐘減小了大約一半!咱們認爲經過調整設置能夠得到更多的好處,但這是一個很好的開始。

固然,每一個決策都須要權衡利弊,pnpm也不例外。雖然pnpm由zkochan積極維護,但與Yarn或NPM相比,它是一個不太受歡迎的項目。雖然微軟使用的是PNPM,但它沒有像Yarn從Facebook得到的直接企業贊助那麼高。和pnpm有本身的lockfile格式,因此它不直接兼容Yarn或NPM。咱們很難知道將來會發生什麼,但若是咱們須要從pnpm中脫離出來,這將是一個比咱們但願的更大的任務。

儘管聽起來很傻,但Yarn不須要自定義腳本的「運行」命令,這使咱們寵壞了,所以咱們不得不從新訓練咱們的肌肉記憶。 這是一個很小的折衷,但它確實增長了咱們的團隊切換這樣一個基本的平常工做流程的成本。

可是,歸根結底,這些成本遠遠超過了pnpm對咱們的堆棧所作出的改進。 如今,咱們能夠比以往更快,更有效地進行工做,而且須要付出的代價更少。

pnpm可能不是適用於每一個項目或每一個堆棧的正確工具,可是若是您遇到與咱們的monorepo相同的任何問題,請看看並考慮將其做爲替代方法。

相關文章
相關標籤/搜索