站長阿川

站長阿川私房教材:
學 JavaScript 前端,帶作品集去面試!

站長精心設計,帶你實作 63 個小專案,得到作品集!

立即開始免費試讀!

Rspack 1.5 發布:十大新特性速覽

ByteDance Web Infra

avatar WebInfra 前端 @字節跳動 Web Infra

image

我們很高興地宣布 Rspack 1.5 已發布!

值得關注的變更如下:

  • 新功能

    • Barrel 檔案優化
    • 更快的檔案系統監聽器
    • 改進瀏覽器支援
    • 使用 Rust 擴展 Rspack
    • 常數內聯優化
    • 類型重導出分析
    • 內建虛擬模組插件
    • 模塊聯邦運行時提升
    • 安裝體積優化
    • Seal 階段性能優化
  • 其他

    • 不再支援 Node.js 16
    • Resolver JavaScript API
  • Rstack 進展

    • Rslint 發布
    • Rsbuild 1.5
    • Rslib 0.12
    • Rspress 2.0 beta
    • Rsdoctor 1.2
    • Rstest 0.2

新功能

Barrel 檔案優化

Barrel 檔案是一種常見的模組導出模式,它透過創建統一的入口檔案來重新導出多個模組,通常命名為 index.jsindex.ts,例如:

export { Button, Tab } from './components';
export * as utils from './utils';
export * from './hooks';

雖然這種模式簡化了模組導入的使用方式,但是在構建過程中會帶來性能問題:當導入 barrel 檔案中的某個模組時,Rspack 需要解析和構建 barrel 檔案依賴的所有模組,即使實際只使用了其中的一小部分。

為了解決這一問題,Rspack 1.5 引入了實驗性的 lazyBarrel 功能,它能夠自動識別無副作用的 barrel 檔案,對其中的重導出進行延遲構建優化,只在真正需要時才會解析和構建相關模組,從而顯著減少不必要的模組解析和構建開銷。這一優化對於包含大量 barrel 檔案的專案尤其有效,能夠帶來顯著的構建性能提升。

// rspack.config.mjs
export default {
  experiments: {
    lazyBarrel: true,
  },
};

在實際測試中,開啟 barrel 檔案優化後,兩個不同規模的應用都獲得了明顯的構建性能提升:

指標 開啟前 開啟後 優化
構建時間 1.47s 1.19s -20%
模組路徑解析次數 39,675 次 20,071 次 -49%
模組構建次數 9,358 次 5,062 次 -46%
  • 來自字節跳動的應用:
指標 開啟前 開啟後 優化
構建時間 17.9s 16.0s -10%
模組路徑解析次數 181,078 次 137,232 次 -24%
模組構建次數 38,046 次 29,405 次 -23%

我們已經在 Rsbuild 1.5 中默認開啟了 barrel 檔案優化,並計劃在 Rspack 1.6 中為所有專案默認啟用該功能。詳見 experiments.lazyBarrel 文檔

更快的檔案系統監聽器

此前,Rspack 使用檔案系統監聽器 watchpack 來監聽檔案變化。在實際使用中,我們發現 watchpack 存在性能瓶頸。例如,每次檔案變更都會重新創建實例,在大型專案中會消耗大量的 CPU 和記憶體資源(參見 #7490)。

為解決這一問題,我們基於 Rust 打造了原生的檔案系統監聽器,新的實現具有以下優勢:

  • 高性能:HMR 速度提升至多 50%
  • 增量更新:只處理實際發生變化的檔案
  • 持久化運行:在整個開發過程中持續工作,無需反覆重建

你可以通過配置 experiments.nativeWatcher 來嘗試新版 watcher:

// rspack.config.mjs
export default {
  experiments: {
    nativeWatcher: true,
  },
  watchOptions: {
    // Other watch options...
  },
};

改進瀏覽器支援

在先前的 Rspack 1.4 中,我們正式引入了 Wasm target 支援,這意味著 Rspack 可以在基於 WebContainers 的瀏覽器環境中運行,例如 StackBlitz

現在你可以直接在任何現代瀏覽器中使用 Rspack了。新發布的 @rspack/browser 是專為純瀏覽器環境設計的版本,而無需依賴 WebContainers 或是特定平台。@rspack/browser 為 Web 專案的在線打包提供底層支援,提供了更輕量的問題復現、配置分享方案,並通過提供在線互動式 Demo 的方式幫助開發者入門和學習 Rspack。

image

@rspack/browser 提供的 API 和 @rspack/core 的 JavaScript API 是對齊的。在此基礎上,額外提供了為適配瀏覽器環境的特性和 API:

import { rspack, builtinMemFs } from '@rspack/browser';

// Write files to memfs
builtinMemFs.volume.fromJSON({
  // ...project files
});

// Just like using JavaScript API of @rspack/core
rspack({}, (err, stats) => {
  if (err || stats.hasErrors()) {
    // ...
  }
  // Get output from memfs after bundling
  const files = builtinMemFs.volume.toJSON();
});

目前 @rspack/browser 還處於實驗性階段,可能會引入不相容更新。未來我們將持續完善在線打包所需的能力,歡迎前往 Rspack Playground 進行體驗。

使用 Rust 擴展 Rspack

現在你可以直接使用 Rust 來擴展 Rspack 了!通過我們提供的倉庫模板,你能夠編寫自定義的 Rust plugin 和 Rust loader,並替換 Rspack 默認的原生 binding。

在 JavaScript 插件中,Rust 和 JavaScript 之間的數據傳遞和類型轉換會產生一定的性能開銷。通過定制 Rspack 的 binding,你的自定義代碼將直接與 Rspack Rust core 集成,消除了跨語言通信的開銷,同時保持對所有 Rspack JavaScript API 的支持。

這種方式適用於替換頻繁與 Rust 通信的 Hooks(如 compilation.hooks.processAssets),以及計算密集型的自定義 loader,在這些場景下可以獲得更好的構建性能。

主要特性:

  • 原生性能 —— Rust 編寫的擴展享受與 Rspack Rust core 相同的原生性能。
  • 完全兼容 —— 保留所有現有的 JavaScript API,無需修改現有專案。
  • 開發便捷 —— 官方模板提供了完整的開發環境和發布流程。

你可以使用 官方模板 快速開始,更多信息請參考 設計理念。需要注意的是,使用此方案會帶來額外的維護成本,建議僅在需要極致性能優化時使用。

常數內聯優化

在組織專案代碼時,我們通常會將常數集中管理,例如 constants.js 或者 TypeScript 專案中包含 enums 的 types.ts 檔案。

Rspack 引入了 experiments.inlineConstexperiments.inlineEnum 兩個實驗性功能,用於對常數進行跨模組內聯優化。這些優化可以幫助壓縮工具更加進行準確的靜態分析,消除無用代碼分支,從而進一步減小產物的體積。

inlineConst 能夠對模組圖中葉子節點模組中的常數進行跨模組內聯,例如以下示例:

// font-settings.js
export const bold = 0b001;
export const italic = 0b010;

// index.js
import { bold, italic } from './font-settings';

const fontStyle = {};
// MY_FONT is defined by DefinePlugin({ FONT: 0b001 })
if (MY_FONT & bold) fontStyle['font-weight'] = 'bold';
if (MY_FONT & italic) fontStyle['font-style'] = 'italic';
applyFont(fontStyle);

啟用 inlineConst 後,示例中的 if 分支能夠明確地被壓縮工具優化,生成更精簡的產物:

(() => {
  'use strict';
  let t = {};
  t['font-weight'] = 'bold';
  applyFont(t);
})();

詳見 experiments.inlineConst 文檔,該功能計劃在 v1.6 中默認啟用。

inlineEnum 會對 TypeScript 的 enums 進行跨模組內聯優化,工作原理與 inlineConst 類似。

// types.ts
export enum Kind {
  A,
  B,
}
// index.ts
import { Kind } from './types.ts';
console.log(Kind.A);

啟用 inlineEnum 後:

(() => {
  console.log(0);
})();

需要注意的是,啟用 inlineEnum 後,Rspack 默認會內聯所有 enums。如果你希望只內聯 const enums,可以參考此 示例

詳見 experiments.inlineEnum

類型重導出分析

在 TypeScript 專案中,類型重導出是一種常見的模式:

// index.ts
export { MyType } from './types.ts';

// types.ts
export type MyType = {
  name: string;
};

在之前的版本中,如果你在重導出類型時沒有添加 type 修飾符,Rspack 可能會拋出警告,例如 export 'MyType' (reexported as 'MyType') was not found

這是因為 Rspack 在解析模組時,採用獨立的方式處理每個模組,導致類型的導出(例子中的 MyType)被錯誤識別為一個值而非類型,由於在 ./types.ts 中找不到相應的值導出,因此觸發了上述警告。

Rspack 1.5 引入了 experiments.typeReexportsPresence 配置,用於改進對 Typescript 類型導出的識別。開啟此配置後,Rspack 能夠正確識別跨模組分析類型重導出,從而避免誤报警告。

詳見 experiments.typeReexportsPresence

內建虛擬模組插件

在 Rspack 1.4 中,我們引入了自定義 InputFileSystem 功能,配合 webpack-virtual-modules 插件可以支持虛擬模組。然而,當虛擬模組數量較大時,該方式仍然存在性能瓶頸。

為了更好地支持虛擬模組,Rspack 1.5 新增了內建的 VirtualModulesPlugin,它基於 Rust 實現,將虛擬模組的存儲和管理遷移到 Rust 層,有效減少了模組讀取和解析的開銷,在處理大量虛擬模組時能夠保持更好的性能表現。

VirtualModulesPluginwebpack-virtual-modules 保持了一致的 API 設計,以便你可以輕鬆地遷移:

// rspack.config.mjs
import { rspack } from '@rspack/core';

export default {
  plugins: [
    new rspack.experiments.VirtualModulesPlugin({
      'src/generated/config.js': 'export default { version: "1.0.0" };',
    }),
  ],
};

感謝我們的社區夥伴 @nilptr貢獻

模塊聯邦運行時提升

此前 Module Federation 的運行時是通過在入口模組打補丁的形式運行起來的。新版的 Module Federation 插件通過將自己的運行時代碼和 Rspack 的運行時代碼合併,同時將 Module Federation 運行時代碼提升到了運行時 chunk 中。這樣能在應用啟動前就將 Module Federation 的運行時提前準備好了。

這樣改動帶來如下收益:

  1. 在多入口的場景下產物尺寸減少
  2. 修復了 Module Federation 初始化出錯的問題
  3. Module Federation 可以提取到運行時 chunk 中
  4. 提供一套基於 hook 的插件體系

下面是一個演示專案在使用新版 Module Federation 插件所帶來的產物體積優化對比。

配置 Before After 優化
Multiple Entries (default) 210kb 210kb 0%
Multiple Entries + runtimeChunk: true 210kb 150kb -29%
Multiple Entries + runtimeChunk: 'single' 210kb 70kb -67%

關於本次 Module Federation 插件的改動詳情,請參閱 這裡

安裝體積優化

自 1.4 以來,我們做了一系列優化來降低 Rspack 的安裝體積,安裝包大小從 Rspack 1.4.0 的 63.7MB 減少到了 Rspack 1.5.0 的 49.9MB

image

其中幾個效果顯著的優化點:

為了進一步優化安裝體積,我們集成了 自動體積檢查 到日常工作流中,持續關注該指標變化。

Seal 階段性能優化

在構建性能方面,Rspack 1.5 針對 Seal 階段(代碼生成和優化的階段)進行了大量優化,通過優化數據結構、提升並行度、增加熱點代碼快取等手段,提升了大型專案的構建性能。得益於並行化優化,在多核機器上性能提升更為顯著。

以字節跳動的某大型應用為例,該專案包含約 40,000 個模組,整體 Seal 階段耗時降低約 50%,各主要階段均有顯著優化:

階段 v1.4.0 v1.5.0 優化
Flag dependency exports 394ms 181ms -54%
Flag dependency usage 1828ms 454ms -75%
Code splitting 2019ms 777ms -62%
Bundle splitting 1588ms 712ms -55%
Module concatenation 2645ms 616ms -76%
Content hash calculation 881ms 404ms -54%

其他

不再支援 Node.js 16

鑑於 Node.js 16 已於 2023 年 9 月 11 日停止維護,同時眾多社區 npm 包(如 webpack-dev-servercss-loadersass-loader 等)也相繼停止了對 Node.js 16 的支援,為了降低維護開銷,Rspack 1.5 將不再支援 Node.js 16。

各包的 Node.js 版本要求變化:

包名 v1.4 v1.5
@rspack/core >=16.0.0 >=18.12.0
@rspack/cli >=18.12.0 >=18.12.0
@rspack/dev-server >=18.12.0 >=18.12.0
@rsbuild/core >=16.10.0 >=18.12.0

⚠️ 這是一個破壞性變更。如果你目前使用的是 Node.js 16,需要升級到 Node.js 18.12.0 或更高版本才能使用 Rspack 1.5。

當前還使用 Node.js 16 的專案,請按照以下步驟進行升級:

  1. 升級 Node.js 版本:建議升級到 Node.js 18.12.0 或更高版本(推薦使用 Node.js 22 LTS)
  2. 更新 CI/CD 配置:請相應地更新你的持續集成配置,確保使用相容的 Node.js 版本

Resolver JavaScript API

為了讓 Rspack 使用者能夠更便捷地使用 Rspack 的模組解析功能,我們已將 rspack-resolver 集成到 Rspack 的 JavaScript API 中,它提供了類似 enhanced-resolve 的模組解析能力。

使用方法請參閱 Resolver API 文檔

穩定化 lazy compilation

經過充分驗證,experiments.lazyCompilation 配置項已從實驗性特性升級為穩定特性,並移動到了 Rspack 配置頂層:

// rspack.config.mjs
export default {
- experiments: {
-   lazyCompilation: true,
- },
+ lazyCompilation: true,
};

原有的 experiments.lazyCompilation 配置仍然可以繼續使用,但會打印一條廢棄警告。

廢棄的選項

Rspack 的 experiments.topLevelAwait 選項用於控制對 top level await 的支援,一直以來都是默認開啟的。經過觀察,我們發現沒有實際場景需要關閉 top level await 支援,因此我們決定廢棄這個選項,並計劃在 Rspack 2.0 中移除它,屆時將無法禁用 top level await 支援。

Rstack 進展

Rstack 是一個以 Rspack 為核心的 JavaScript 統一工具鏈,具有優秀的性能和一致的架構。

Rslint 發布

image

我們很高興地宣布 Rslint 的發布!
Rslint 是一個 TypeScript 優先的新一代 Linter,由 Go 編寫,並基於 typescript-go 提供的類型檢查能力。
它起源於 @auvred 開發的 tsgolint,並在此基礎上進行了擴展和優化。

Rslint 目前支持如下功能:

  • ESLint 風格的配置與指令:幾乎無縫上手
  • IDE 支持:提供 VS Code 插件,支持 Cursor、Trae 等 IDE
  • 自動修復:rslint --fix 一鍵修復代碼問題
  • 規則支持:已實現 50+ 條 @typescript-eslint 規則
  • 測試驗證:運行原始 typescript-eslint 測試套件,確保規則正確性

Rslint 仍處於早期階段,我們正在積極開發更多功能和規則支持。歡迎大家嘗試使用,並給予寶貴的反饋,幫助我們一起打磨 Rslint!

Rsbuild 1.5

開箱即用一直是 Rsbuild 的核心設計理念。在 Rsbuild 1.5 中,我們默認啟用了多項 Rspack 的最新特性,帶來更優秀的構建性能,包括:

  • 啟用 lazyCompilation 來按需編譯動態導入的模組,這可以提升開發伺服器的啟動速度。
  • 啟用 lazyBarrel 來優化 barrel 檔案的構建速度,減少不必要的模組解析。
  • 啟用 inlineEnum 來內聯 TypeScript 枚舉,這可以減少枚舉被編譯後的包體積。
  • 啟用 typeReexportsPresence 來正確識別 TypeScript 類型重導出,提升類型處理的準確性。

將 Rsbuild 升級至最新版本後,上述特性將默認啟用,無需任何額外配置。

Rsbuild 1.5 還新增了 output.module 選項,用於輸出 ES modules 格式的構建產物。

目前該選項針對 Node.js bundles 提供了 ESM 格式支持,未來我們將繼續增加對 web 應用 ESM 格式的支持。

// rsbuild.config.ts
export default {
  output: {
    target: 'node',
    module: true,
  },
};

Rslib 0.12

在 Rslib 0.12 版本中,我們在專案模板中集成了 Rstest 測試框架。如果需要,你可以使用 Rstest 來測試你的庫專案,通過統一的 Rstack 工具鏈進行開發和測試。

image

此外,我們正在積極設計並開發全新的 ESM 產物生成方案,旨在提供類似 esbuild 和 Rollup 的 ESM 產物質量,同時保持與 webpack 一致的 interop 行為以確保正確性。詳見 interop 測試

Rspress 2.0 beta

Rspress 2.0 目前處於 beta 階段,開發工作接近尾聲,我們計劃在兩個月內發布正式版本。

最新 beta 版本新增了 Markdown 文本複製組件,方便使用者將文檔內容提供給大模型進行分析和處理,你可以在各個 Rstack 文檔站點體驗這個功能:

image

該功能基於 @rspress/plugin-llms 插件實現,自動生成符合 llms.txt 標準的檔案,使用方法請參考 @rspress/plugin-llms 文檔

Rsdoctor 1.2

Rsdoctor 1.2 版本帶來了多項重要更新,新增了對聚合模組的精確分析能力,以及帶來全新的 Treemap 視圖。這些功能提升了構建產物分析的準確性和可視化體驗,可以幫助你更好地理解和優化專案的打包產物。

請查看 Rsdoctor 1.2 發布博客 了解更多。

Rstest 0.2

經過兩個月的持續迭代和 10 多個版本的優化,Rstest 0.2 在功能和穩定性方面都有了顯著改進,帶來以下新特性:

  • Mock API:Rstest 現在提供了完整的 mock API,用於在測試環境中替換模組的實際實現,支持對 ES 模組進行模擬操作。
  • Watch 模式優化:在 watch 模式下,Rstest 現在支持增量重新運行。當測試檔案或其依賴的模組發生變化時,Rstest 會只重新運行相關的測試檔案,從而提升測試執行效率。
  • CLI 快捷鍵

原文出處:https://juejin.cn/post/7542769726175969280


共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
站長阿川

站長阿川私房教材:
學 JavaScript 前端,帶作品集去面試!

站長精心設計,帶你實作 63 個小專案,得到作品集!

立即開始免費試讀!