Rspack 是一個很好的技術話題,也是未來的播客嘉賓,這裡做個快速了解。
這次帶讀的是字節跳動 Rspack 的原理與實踐,字節跳動楊健
楊健 - 字節跳動 Rspack 的原理與實踐
官網 rspack.dev
以下是一些分享內容的原文和感受,原文我會註明,以感受為主。
原文大綱
- 為什麼選擇 Rspack
- 特性
- 生態兼容
- 開箱即用的能力
- 業務性能收益
- 架構設計
- 遷移指南
為什麼選擇 Rspack#
webpack 不夠好#
公司內部有很多巨型應用,項目啟動慢,冷啟動慢、構建慢。
傳統的 webpack 優化手段已經老套,例如 babel -> swc-loader,例如 esbuild/vite 等。
這些方案有優勢,但不能完全解決問題。例如 swc-loader 可以加速 loader,但不全面。
vite 的 dev 快,但是 rollup 構建速度並不比 webpack 快。
esbuild 在生產優化方面很快,但是不支持 dev-hmr,打包能力和插件能力都比較弱,無法滿足拆包需求。
這裡回答了 vite 和 rspack 哪個更好的問題,這個問題沒有答案。要看場景和極端表現。例如開發體驗、ssr,但是重型項目的構建就有差異。
但是 rspack 本身偏向底層,vue-cli 遷移可能會麻煩一些。
好的構建工具應該是什麼樣的#
也就是開發者的需求
- 性能要好,冷啟動快、hrm 快、構建快,即使構建數十次也要快。
- 靈活性,配置要靈活,應對不同的使用場景。對於 toC 構建產物大小和 toB 巨型應用的可擴展性。
- 生產產物性能:code splitting 拆包、treeShaking、首屏加載等。
- 應用場景,webapp+node.js + 跨平台。
- 遷移成本要低,業務方不抗拒。
從這些需求來看,webpack 是最好的選擇,例如 swc/esbuild/vite 等工具面對傳統項目和跨平台項目還有很長的路要走。
rspack 說我來!#
rspack 有很多優點:
- 使用 rust 實現,原生能力強
- 增量編譯、hrm 快
- webpack 生態兼容
- 開箱即用支持 ts/tsx/css/css modules,不需要自己找插件了
- 默認多種優化策略,包括 tree shaking/code splitting 代碼壓縮等
兼容性好,舉例了一部分。那麼我們常見的插件都可以使用。
另外,不需要自己折騰 ts 了,默認的就很好用,不需要 babel-loader/ts-loader 了,這是以前的噩夢。
以前處理 css 很麻煩,需要抽包、css/style loader 等,現在也內置了,又快又好用,但是 less/sass 還需要配置,有一個對比截圖,rspack 簡單一些,主要是 less-loader 結束後的產物直接設定 css 和 css/module 由內置處理。
講完兼容性,性能收益好,三個指標冷啟動 dev、hrm、生產構建 build。
給了一張圖,不放了,就是 rspack 表現很不錯。特別是生產構建 rollup 還是不行。
收益#
講完測試,講落地。內部項目測試結果顯示有巨大提升,相較於 webpack 提升了 10 倍。
webpack 中一個 hrm 需要 20 秒,不敢想像...,優化後只需要 1 秒。
常見問題#
所以可以回答一些常見問題:
為什麼不是 node + js?#
- webpack 多年來單線程努力,性能壓榨有限
- node 本身是單線程,本身不支持多線程
- 使用 worker-thread 支持多線程,背後是創建新的 v8 實例模擬單線程。通信過程需要序列化和反序列化,數據共享效率不高
- 並發生態匱乏
由於 v8 的多線程支持不夠好,性能消耗大,並發編程生態匱乏
為什麼不是 golang - esbuild?#
- golang 的性能滿足需求
- 對 napi 的支持不好,無法滿足需求
- esbuild 不提供操作 ast 的 api,不支持降級 es5
為什麼選擇 rust?#
- 性能好
- 對 napi 的支持好,rust 宏支持,少寫樣板代碼
- rust 對 webAssembly 的支持好,甚至 rust 推動更激進領先
- rust 的 swc 對 ast 的操作支持豐富,也支持降級 es5
swc 就好了嗎?#
大公司展示實力,
- 發現 swc 並發解析差,發現 dev 的 profiler 發現 parsing 是瓶頸,進一步發現了底層庫的 bug
為什麼還要使用 js 做插件擴展呢#
- js 熟悉,rust 不熟悉,成本高,無法滿足靈活多變的需求
- 動態化特性,rust 的動態性不如 js,例如編譯產物可能和機器環境相關,可能有差異,跨平台的處理麻煩,可能需要編譯出十幾個平台的產物,門檻高,穩定性也不夠強
快的原理#
- 架構基於 Webpack 5
- 採用 rust
- babel 換成 swc,loader 太慢了,大家一般使用 swc/esbuild 提速。
- rust 和 js 使用 napi-rs 通信,v8 是基於 buffer string 通信,多線程支持不好,複雜的數據結構通信困難,例如 ast 只能選擇序列化通信。序列化反序列化開銷巨大。但是 rust 多線程共享簡單,沒有什麼開銷。多核表現優異。
放了一張架構圖,我沒見過,說是和 webpack 架構圖差不多。(這裡我沒經歷過,我聽了兩次)
make pase 構建依賴圖 module graph
/seal phase 階段。依賴圖生成 chunk
- 優化分析,分析模塊使用、副作用
- chunk 圖形創建
- 分包、模塊圖
- id 生成
- 生成模塊 id
- 生成 chunk id
- 模塊代碼生成
- 運行時模塊
- chunk 資源生成
- 生成資源
分包緩存策略,要和業務區分,拆包並行加載。
用戶配置 polyfill es5-es6-esnext 等
這一部分很精彩,第一次聽。
黃色部分都是可以並行處理的,rust 做得比較快。webpack 做不好的一個原因是對多線程處理不好,使用 thread-loader 也會通信費勁,但是 rspack 兩個缺點都解決了。
核心:一切能並行的地方都並行。多核提升一倍,能有 1.7 倍的提升,當然還是有損耗的。但是比 webpack 提升有限,例如 1.1 倍 - 1.2 倍的提升有限。
老業務遷移#
- 內置的功能要使用,例如 js/ts/css/file-loader/html-plugin 等
- 例如 html-plugin 插件的靈活度不夠好,畢竟 html 那個業務都想塞點東西進去,所以這裡也內置了一個 js 版本的插件用來方便擴展,稍慢但靈活
- 第三方插件不支持,可以跟進
roadmap 展望
- webpack 生態兼容
- 更多框架支持
- 支持持久化緩存 persistent cache、懶編譯 lazy compilation
- 更多生產優化
- 支持 mf
聽完的展望#
呼,帶讀了 webpack 的架構,指出了優化方向,那麼 rspack 就是這樣做的。
尊敬深厚經驗,細節還是不懂,得多看。