Parcel 2 beta 3

Parcel 團隊很興奮地發布 Parcel 2 beta 3!此版本包含用 Rust 重寫的 JavaScript 編譯器,將整體建置效能提升了 10 倍。此外,這篇文章將介紹自上次更新以來我們對 Parcel 做的一些其他改進,以及我們邁向穩定的 Parcel 2 版本的路線圖。

以 Rust 編寫的 JavaScript 編譯器快了 10 倍 🚀

#

在過去幾個月中,我們一直在用 Rust 重寫我們的 JavaScript 編譯器!Parcel 的 JavaScript 編譯器負責偵測程式碼中的依賴項(例如 import 陳述式和 new Worker() 呼叫),內嵌 process.env 變數和其他 Node 全域變數,並執行範圍提升。

此外,Parcel 會根據您設定的 browserslist 目標自動轉譯您的原始碼,以及非標準語法(例如 JSX 和 TypeScript)和開發功能(例如 React 快速更新)。

先前,所有這些都實作在 Babel AST 上方的 JavaScript 中。儘管我們 大幅 進展最佳化這個部分,但 JavaScript 編譯仍然是 Parcel 中最慢的部分。特別是,將大型 JavaScript AST 序列化以在執行緒間傳送非常慢,而且這些大型物件對 JavaScript 垃圾收集器造成很大的壓力。此外,JavaScript 程式碼每次執行時都必須由引擎編譯,這表示啟動很慢。儘管改善演算法複雜度將導致效能改善,無論語言為何,但這只能帶你到此為止。

Parcel 的新 JavaScript 轉換器是以 Rust 編寫在 SWC 編譯器之上。SWC 提供 JavaScript 解析和程式碼產生,以及建立超快速 AST 轉換的穩固基礎。Rust 提供可預測的效能、立即啟動時間,以及最佳化到硬體層級的能力。

此外,範圍提升連結器現在只在字串上執行,而不是 AST,這也大幅改善效能,因為我們避免序列化和取消序列化這些大型物件。這也允許程式碼產生在所有檔案中平行化,而不是一次在整個套件中執行。

整體而言,這將建置效能提升多達 10 倍!

在 ESBuild 基準測試中,Parcel 現在在沒有 Terser 的情況下快了約 10 倍,在啟用縮小的情況下快了約 3 倍。

Chart showing performance of previous beta vs rust rewrite. Without terser, previous beta took 34s and the rust rewrite took 3.2s. With terser, the previous beta took 56s and the rust rewrite took 18s.

轉譯效能

#

此外,當設定 browserslist 時,SWC 預設取代 Babel 進行轉譯,以及編譯 JSX 和 TypeScript,以及 React 快速更新。SWC 比 Babel 快 20 倍,因此這個變更也應該大幅改善整體效能。

雖然 SWC 是預設值,但請放心,Babel 仍然受到支援。如果您在專案中擁有自訂 Babel 組態,它仍會自動使用。這表示自訂 Babel 外掛程式(例如 CSS-in-JS 轉換、Babel 巨集等)會繼續開箱即用。範圍提升、相依性收集,以及之前內建於 Parcel 中的所有其他功能現在會在 Rust 中執行,但這應該會完全透明。

不過,這確實開啟了進一步提升建置效能的可能性。您現在可以從 .babelrc 中移除 @babel/preset-env@babel/preset-react@babel/preset-typescript,而 SWC 會自動處理它們。這可以大幅提升您的建置效能。如果您有其他自訂 Babel 外掛程式,您可以將它們留在您的 Babel 組態中。如果不是,您可以完全刪除您的 Babel 組態。我們未來可能會新增一個警告來協助進行此遷移。

範圍提升改進

#

除了效能之外,我們在舊的範圍提升實作中遇到了一些問題,這促使我們重新撰寫。特別是,包括 Parcel 在內的幾個 JavaScript 捆綁器都與在同時使用範圍提升和程式碼分割時執行順序相關的 錯誤

範圍提升是將多個 JavaScript 模組合併成單一範圍的程序。這讓無用程式碼消除(又稱樹狀搖晃)更有效率,並透過讓跨模組參照成為靜態的,而非動態的屬性查詢,來提升執行時期效能。

當將多個模組提升到同一個範圍,而非將每個模組包裝在一個獨立函式中時,要確保這些模組在跨捆綁器參照時總是按照正確順序執行會變得困難。

此外,有時會在多個捆綁器之間重複小型模組,以避免產生許多非常小的輸出檔案,並增加載入頁面所需的 HTTP 要求數量。以前,這可能會導致模組執行超過一次,這可能會破壞許多事情,包括副作用(例如變異 DOM)和單例模式。

為了修復這些問題,必須從頭開始重新思考我們的範圍提升編譯器的工作方式。結果是範圍提升的混合體,在我們可以的地方,但需要時會退回包裝 CJS 風格函數的模組,並使用全域模組註冊表。這可確保在套件之間引用的模組按正確順序執行,且重複的模組只執行一次。

如果您有興趣進一步了解我們的範圍提升實作運作方式,請查看設計文件,其中詳細說明所有這些主題。

樹狀搖晃動態導入

#

與我們的範圍提升實作相關的另一個功能是支援樹狀搖晃動態 import()。Parcel 可以偵測動態導入的哪些屬性被存取,並排除已解析模組中未使用的匯出。這適用於承諾鏈接、非同步/等待、解構和靜態物件屬性存取。如果任何內容是非靜態存取的,例如計算屬性,則會包含所有匯出。

Example of tree shaking dynamic import

樹狀搖晃 CSS 模組

#

我們現在也支援樹狀搖晃 CSS 模組。當您在 JavaScript 中導入 CSS 模組時,Parcel 會追蹤哪些類別被使用,並自動從已編譯 CSS 檔案中排除未使用的選擇器。此外,類別名稱現在會自動內嵌在已編譯 JavaScript 中,而不是儲存在大型物件對應中。這應有助於減少 CSS 和 JS 輸出的套件大小!

Example of tree shaking CSS modules

延遲開發建置

#

在開發過程中,等待整個應用程式建置完成才能啟動開發伺服器是一件令人沮喪的事。尤其是在處理有多個頁面的大型應用程式時更是如此。如果你只處理一個功能,為什麼需要等待所有其他功能都建置完成,除非你實際瀏覽到它們?

Parcel 現在支援在使用開發伺服器時使用 --lazy CLI 標記。啟用後,Parcel 只會建置依要求提供的檔案,這可以大幅減少開發建置時間。伺服器會立即啟動,當你第一次瀏覽到某個頁面時,Parcel 只會建置該頁面所需的檔案。當你瀏覽到另一個頁面時,該頁面將依要求建置。如果你瀏覽回先前已建置的頁面,它會立即載入。

這也適用於動態 import(),而不仅仅是完全分開的頁面。因此,如果你有一個具有動態載入功能的頁面,該功能將在啟用後才會建置。Parcel 足夠聰明,可以一次急切地建置所有請求檔案的相依性,而不用等待它們也被請求。如果你有一些與 JavaScript 搭配的 CSS,或一些參考的圖片,它們都將一起建置,不會有網路瀑布效應!

當然,權衡取捨是頁面載入和動態載入在第一次載入時可能會稍微慢一些。但是透過 Parcel 的磁碟快取,這應該只會發生一次。即使你重新啟動 Parcel,也不需要重新建置未變更的檔案。

快取可靠性

#

談到快取,另一個我們一直在努力的領域是快取可靠性。我們希望使用者信任快取,因此我們需要確保所有可能使快取失效的事物實際上都會使快取失效。這比聽起來困難多了。現代 JavaScript 建置工具有許多輸入需要追蹤,包括磁碟上的檔案、組態、環境變數、用於編譯程式碼的開發依賴關係,以及更多。當其中任何一項變更時,Parcel 需要使快取失效並重新計算輸出。

Parcel 在圖形中追蹤所有這些輸入。我們的檔案監控器會監控磁碟上的變更,並使任何與變更檔案相關的請求失效。當您重新啟動 Parcel 時也會發生這種情況。我們的監控器會與作業系統層級的 API 整合,以快速判斷自您上次執行 Parcel 以來哪些檔案已變更,這表示重新啟動 Parcel 幾乎和使用監控模式一樣快!

開發依賴關係 HMR

#

所有這些快取失效工作的附帶好處是監控模式也受益。我們已實作的一項很酷的功能是Parcel 外掛程式的 HMR和其他建置依賴關係。當您變更外掛程式原始碼時,我們會重新載入外掛程式並重新建置它先前已編譯的任何檔案。這使得處理外掛程式並立即看到變更變得非常快速,無需重新啟動 Parcel。

它也適用於 Babel 外掛程式、PostCSS 外掛程式,以及建置中涉及的任何其他開發依賴關係。您甚至可以在 node_modules 中編輯外掛程式,而 Parcel 會自動重新編譯。當您需要在建置管線中偵錯某些內容,或使用 patch-package 等工具時,這很有用。

更少的依賴關係

#

Parcel 預設支援許多不同的語言和工具,這讓入門變得非常容易。但這也有個缺點,就是安裝 Parcel 會包含許多你可能用不到的依賴項。這不僅會耗用磁碟空間和網路頻寬,也增加了你維護和稽核的依賴項。

我們希望減少 Parcel 的依賴項,同時保持其易於使用的特性。為此,我們現在預設只安裝必要的外掛,並依需求自動安裝其他外掛到你的專案中。

預設情況下,我們包含對 HTML、CSS 和 JavaScript 等標準網頁語言的支援。但是,只要你包含 Parcel 識別的 SASS 檔案、Vue、Elm、CoffeeScript 或任何其他檔案類型,我們就會自動安裝必要的外掛和所有對等依賴項到你的專案中。這讓 Parcel 非常容易使用(零設定),但也會減少專案中的依賴項數量。

路線圖

#

Parcel 2 已開發幾年了,我們並未總是盡力更新社群有關我們穩定版本路線圖進度的資訊。因此,本節將更新我們的進度。

Beta 3 很可能將是我們第一個候選版本前的最後一個 beta 版本,我們希望它將在大約一個月後推出。對於第一個 rc,我們正在處理以下事項

在 rc 之後,公開 API 將會凍結,我們將專注於錯誤修正和文件。這有望在大約一個月內完成。準備好後,我們將發布 2.0!

在這個時候,綑綁器、執行環境和驗證器的外掛 API 很可能會在 Parcel 2.0 中標記為實驗性。這表示這些功能將不遵循 semver,我們將在 Parcel 2 初始穩定版本發布後繼續迭代它們。此外,我們計畫在 2.0 之後推出許多其他功能和改進,包括進一步的效能最佳化。

謝謝!

#

一如往常,感謝您試用我們的測試版,並在 GitHub 上提供意見回饋。您也可以捐款給我們的 開放集體,這有助於支持我們的貢獻者。