舊的架構是一個相當簡單的版本,只支援一般階段的載入器。它沒有考慮到投放載入器(pitching loader)。舊版本的基本概念是將一般載入器轉換為可以從 Rust 端呼叫的原生函式。此外,為了效能考量,Rspack 也會從 JS 端組合載入器,以減輕 Node/Rust 通訊的效能問題。
在這個新的架構中,載入器不會直接轉換為原生函式。相反地,它幾乎與 webpack 的 loader-runner 如何解析其載入器的方式相同,藉由利用識別符。每次 Rspack 想要調用 JS 載入器時,識別符會被傳遞到 Node 端傳遞的處理器進行處理。實作也保留了組合 JS 載入器的功能以提高效能。
這次重構沒有引入任何其他重大變更。因此它是向後相容的。架構的變更也幫助我們實作具有可組合性的投放載入器。
投放載入器是一種改變載入器管線流程的技術。它通常與內聯載入器語法一起使用,以建立另一個載入器管線。style-loader 等,以及其他可能會消耗後續載入器評估結果的載入器可能會使用此技術。還有其他技術可以達到相同的功能,但這超出本文的主題。
請參閱投放載入器以取得更多詳細資訊。
在載入器的原始實作中,Rspack 會首先轉換一般載入器,然後將其傳遞到 Rust 端。在建置模組的過程中,這些載入器會被直接呼叫。
載入器執行器僅在 Rust 端,並直接從 Rust 端執行載入器。這種機制強烈限制我們使用 webpack 的 loader-runner 進行組合載入器。
在新的架構中,我們會將來自 Rust 核心的載入器請求委派給位於 JS 端的分配器。分配器會正規化載入器,並使用修改版的 webpack 的 loader-runner 來執行這些載入器。
用於投放或一般的載入器函式不會傳遞到 Rust 端。相反地,每個 JS 載入器都有其唯一的識別符來表示。如果模組請求載入器來處理模組,Rspack 會將帶有選項的識別符傳遞到 JS 端,以指示類似 Webpack 的載入器執行器來處理轉換。這也降低了編寫我們自己的載入器組合器的複雜性。
選項通常會轉換為查詢,但某些選項包含無法序列化的欄位,Rspack 會重複使用 webpack 建立的載入器識別符來唯一識別選項,並在後續載入過程中還原它。
正如我們之前所知,每個載入器都有兩個步驟:投放和一般。為了實現效能友好的互通性,我們必須盡可能減少 Rust 和 JS 之間的通訊。通常,載入器的執行步驟會像這樣
上述載入器的執行順序如下:
上面的範例不包含任何 JS 載入器,但如果,例如,我們將這些載入器標記為在 JS 端註冊
執行順序不會改變,但 Rspack 會將步驟 2/3/4 組合在一起,只進行單輪通訊。