都在卷打包工具?Rspack 又有什么特性?
Hello,大家好,我是 Sunday。
Webpack 作為最經典的 前端打包工具,這幾年過的可真是不太平。
前有 Vite 出現,號稱可以 “顛覆 webpack”。后有webpack創始人推出新的打包工具 Turbopack,號稱比 webpack 快 700 倍。
這不,三天前(8月28日),字節跳動也推出了全新的打包工具 Rspack,號稱 能夠無縫替換 webpack, 并提供閃電般的構建速度
圖片
那么到目前為止,Rspack 也正式推出 3 天了,所以今天咱們就來看看它吧!
制作 Rspack 的初衷
根據原生團隊描述:Rspack 的推出,最初是為了解決字節內部 巨石應用 的問題。
使用 webpack 時,每次編譯都需要耗時 十幾分鐘,甚至半個小時的時間,并且基于 webpack 的優化收效甚微,因此才有了構建 Rspack 的需求。
整個構建的過程,遵循以下 4 個標準:
- 快速的 Dev 啟動性能:npm run dev 是開發者每天需要運行很多次的命令,但大型項目每次都需要等待 10 分鐘,這對于工程師來說非常痛苦,因此優化開發模式下啟動的時間至關重要。
- 高效的 Build 性能:npm run build 經常在 CI/CD 環境中運行,它決定了應用生產交付的效率。有些應用在生產環境中需要 20 到 30 分鐘的構建時間,如果能縮短這段時間,對開發流程也將非常有幫助。
- 靈活的配置:用戶工程的配置非常靈活,不夠統一。在之前的嘗試中,將 webpack 配置遷移到其他構建工具時,我們遇到了許多問題,因為其他構建工具的配置不如 webpack 靈活。
- 生產環境的優化能力:在啟用 Rspack 之前,我們嘗試了社區內的各種方案,但它們都面臨著一定程度的生產環境負優化,例如拆分包不夠精細等。因此,優化生產環境的產物是我們不可放棄的功能。
體驗下 Rspack
整個 Rspack 的使用場景主要分為兩種:
- 直接使用 Rspack 創建全新項目
- 從一個基于 webpack 的項目遷移到 Rspack。畢竟 Rspack 號稱可以 “無縫替換 webpack”。如果大家也在現有項目中飽受 編譯過慢 的問題,那么不妨可以進行一下嘗試。
直接使用 Rspack 創建全新項目
這種操作比較簡單,與使用 vue-cli、vite、CRA 的區別并不大
官方 推薦使用 Rsbuild 創建項目
Rsbuild 是由 Rspack 驅動的高性能構建工具,由 Rspack 團隊開發。它默認包含了一套精心設計的構建配置,提供開箱即用的開發體驗,并能夠充分發揮出 Rspack 的性能優勢。
npm create rsbuild@latest
從 webpack 中遷移
這應該是很多同學真正的痛點了。
如果大家也在現有項目中飽受 編譯過慢 的問題,那么不妨可以進行一下嘗試。
在這里,Rspack 提供了多種遷移方案:
圖片
我們以 vue-cli 為例,整個遷移過程比較平滑:
1. 安裝依賴
首先你需要把 Vue CLI 的 npm 依賴替換為 Rsbuild 的依賴。
移除 Vue CLI 的依賴:
npm remove @vue/cli-service @vue/cli-plugin-babel @vue/cli-plugin-eslint core-js
安裝 Rsbuild 的依賴:
npm add @rsbuild/core @rsbuild/plugin-vue -D
如果你的項目是基于 Vue 2 的,請將 @rsbuild/plugin-vue 替換為 @rsbuild/plugin-vue2。
2. 更新 npm scripts
下一步,你需要把 package.json 中的 npm scripts 更新為 Rsbuild 的 CLI 命令。
{
"scripts": {
- "serve": "vue-cli-service serve",
- "build": "vue-cli-service build",
+ "serve": "rsbuild dev",
+ "build": "rsbuild build",
+ "preview": "rsbuild preview"
}
}
Rsbuild 未集成 ESLint,因此沒有提供用于替換 vue-cli-service lint 的命令,你可以直接使用 ESLint 的 CLI 命令 作為替代。
3. 創建配置文件
在 package.json 的同級目錄下創建 Rsbuild 的配置文件 rsbuild.config.ts,并添加以下內容:
import { defineConfig } from '@rsbuild/core';
import { pluginVue } from '@rsbuild/plugin-vue';
export default defineConfig({
plugins: [pluginVue()],
source: {
// 指定入口文件
entry: {
index: './src/main.js',
},
},
});
如果你的項目是基于 Vue 2 的,請使用 import { pluginVue2 } from '@rsbuild/plugin-vue2';。
4. HTML 模板
Vue CLI 默認使用 public/index.html 文件作為 HTML 模板。在 Rsbuild 中,你可以通過 html.template 來指定 HTML 模板:
// rsbuild.config.ts
export default defineConfig({
html: {
template: './public/index.html',
},
});
在 HTML 模板中,如果使用了 Vue CLI 的 BASE_URL 變量,請替換為 Rsbuild 的 assetPrefix 變量,并使用斜杠進行連接:
- <link rel="icon" href="<%= BASE_URL %>favicon.ico">
+ <link rel="icon" href="<%= assetPrefix %>/favicon.ico">
這樣就完成了從 Vue CLI 到 Rsbuild 的基本遷移,此時你可以執行 npm run serve 命令來嘗試啟動開發服務器。
5. 配置遷移處理方案
部分配置方案需要進行替換:
圖片
6. 環境變量處理方案
Vue CLI 默認會將 VUE_APP_ 開頭的環境變量注入到 client 代碼中,而 Rsbuild 默認會注入 PUBLIC_ 開頭的環境變量(參考 public 變量)。
為了兼容 Vue CLI 的行為,你可以手動調用 Rsbuild 提供的 loadEnv 方法來讀取 VUE_APP_ 開頭的環境變量,并通過 source.define 配置項注入到 client 代碼中。
// rsbuild.config.ts
import { defineConfig, loadEnv } from '@rsbuild/core';
const { publicVars } = loadEnv({ prefixes: ['VUE_APP_'] });
export default defineConfig({
source: {
define: publicVars,
},
});
和其他構建工具的對比
每個工具出現之后,都會和其他的工具對比一番,并借此描述出 “自己的各種優勢”。
因此,這種對比可能并沒有那么的“公正(畢竟大佬針對特定場景下性能問題的撕逼情況也并不少見)”。因此 該部分僅供參考
和 webpack 的區別
webpack 是目前最為成熟的構建工具,有著活躍的生態,靈活的配置和豐富的功能,但是其最為人詬病的是其性能問題,尤其在一些大型項目上,構建花費的時間可能會達到幾分鐘甚至幾十分鐘,性能問題是目前 webpack 最大的短板。因此 Rspack 解決的問題核心就是 webpack 的性能問題。 Rspack 比 webpack 快得益于如下幾方面:
- Rust 語言優勢: Rspack 使用 Rust 語言編寫, 得益于 Rust 的高性能編譯器支持, Rust 編譯生成的 Native Code 通常比 JavaScript 性能更為高效。
- 高度并行的架構: webpack 受限于 JavaScript 對多線程的羸弱支持,導致其很難進行高度的并行化計算,而得益于 Rust 語言的并行化的良好支持, Rspack 采用了高度并行化的架構,如模塊圖生成,代碼生成等階段,都是采用多線程并行執行,這使得其編譯性能隨著 CPU 核心數的增長而增長,充分挖掘 CPU 的多核優勢。
- 內置大部分的功能: 事實上 webpack 本身的性能足夠高效,但是因為 webpack 本身內置了較少的功能,這使得我們在使用 webpack 做現代 Web App 開發時,通常需要配合很多的 plugin 和 loader 進行使用,而這些 loader 和 plugin 往往是性能的瓶頸,而 Rspack 雖然支持 loader 和 plugin,但是保證絕大部分常用功能都內置在 Rspack 內,從而減小 JS plugin | loader 導致的低性能和通信開銷問題。
- 增量編譯: 盡管 Rspack 的全量編譯足夠高效,但是當項目龐大時,全量的編譯仍然難以滿足 HMR 的性能要求,因此在 HMR 階段,我們采用的是更為高效的增量編譯策略,從而保證,無論你的項目多大,其 HMR 的開銷總是控制在合理范圍內。
和 Vite 的區別
Vite 提供了很好的開發者體驗,但 Vite 在生產構建中依賴了 Rollup ,因此與其他基于 JavaScript 的工具鏈一樣,面臨著生產環境的構建性能問題。
另外,Rollup 相較于 webpack 做了一些平衡取舍,在這里同樣適用。比如,Rollup 缺失了 webpack 對于拆包的靈活性,即缺失了 optimization.splitChunks 提供的很多功能。
和 esbuild 的區別
我們在內部進行過大規模地將 esbuild 作為通用的 Web App 構建工具的實踐,但是遇到如下一些問題:
缺乏對 JavaScript HMR 和增量編譯的良好支持,這導致大型項目中的 HMR 性能較差。拆包策略也非常原始,難以滿足業務復雜多變的拆包優化需求。
和 Turbopack 的區別
Rspack 和 turbopack 都是基于 Rust 實現的 bundler,且都發揮了 Rust 語言的優勢。
與 turbopack 不同的是,Rspack 選擇了對 webpack 生態兼容的路線,一方面,這些兼容可能會帶來一定的性能開銷,但在實際的業務落地中,我們發現對于大部分的應用來說,這些性能開銷是可以接受的,另一方面,這些兼容也使得 Rspack 可以更好地與上層的框架和生態進行集成,能夠實現業務的漸進式遷移。
和 Rollup 的區別
Rspack 和 Rollup 雖然都是打包工具,但是兩者的側重領域不同,Rollup 更適合用于打包庫,而 Rspack 適合用于打包應用。因此 Rspack 對打包應用進行了很多優化,如 HMR、Bundle splitting 等功能,而 Rollup 則比 Rspack 的編譯產物對庫更為友好,如更好的 ESM 產物支持。 社區上也有很多的工具在 Rollup 基礎上進行了一定的封裝,提供了對應用打包更友好的支持,如 vite 和 wmr, 目前 Rspack 比 Rollup 有更好的生產環境構建性能。
和 Parcel 的區別
Rspack 的整體架構與 Parcel 有很多共同之處。例如都將 CSS 資源視為一等公民,都支持基于 filter 的 transformer。然而,Parcel 更加注重開箱即用的體驗,而 Rspack 更加注重為上層框架提供靈活的配置。Parcel 開創性地設計了 Unified Graph 和使 HTML 成為一等公民的特性。Rspack 也計劃在未來支持這些特性。