Webpack 遷移 Rspack 速攻實戰教程(前瞻版)

題圖:Speed Crab。

rspack 即將開源,但社區中不乏有已經落地的 case ,比如 rspack-migration-showcase 、 modern.js 等。

基於此,本文將介紹如何遷移一個近似於 CRA( create-react-app ) 的項目到 rspack 。

在閱讀本文前,我們認爲讀者已經熟練掌握了 webpack 配置,本文將略過所有前置知識。

注:由於 rspack 處於 0.0.x 版本,可能會發生較大變化,故本文可能存在過時的部分,請仔細甄別。

啓動層

啓動層分 實例實現 和 DevServer 實現,他們的區別是:

webpack

// webpack 實例
import webpack from "webpack";
webpack();
// webpack dev server
import WebpackDevServer from "webpack-dev-server";
WebpackDevServer();

rspack

// rspack 實例
import * as rspack from "@rspack/core";
rspack.rspack();
// rspack dev server
import * as rspackDevServer from "@rspack/dev-server";
rspackDevServer.RspackDevServer();
// 🔴 不支持合成導入
// import rspack from 'rspack'
// import rspackDevServer from '@rspack/dev-server'

無論是 webpack 還是 rspack ,在啓動層幾乎一致,通過 實例實現 傳入配置得到 compiler ,即可引導啓動 DevServer 或進行構建,細節略:

// 獲取 compiler
const instanceImpl = rspack.rspack; // or `webpack`
const compilerImpl = instanceImpl(webpackConfig);
// 獲取 dev server
const devServerImpl = rspackDevServer.RspackDevServer; // or `WebpackDevServer`
const devServer = devServerImpl(devServerConfig, compilerImpl);

可以看到兩者無明顯區別,需要注意的是使用 compiler 的後續 api 可能存在 rspack 未支持的情況。

配置層

配置類型

兩者配置類型獲取方式:

import type { Configuration as WebpackConfig } from "webpack";
import type { Configuration as RspConfig } from "@rspack/core";

基本一致的配置項

這裏指的是直接把 webpack 的配置原模原樣拷貝給 rspack 也可以兼容的選項,經作者嘗試,常用選項如下:

有區別的配置項

webpack 的複雜配置需要進行一些調整才能給予 rspack 使用。

1、resolve

rspack 的 resolve 配置項要在 webpack 的基礎上加一個 tsConfigPath ,表示當前項目 tsconfig.json 的路徑:

  rspackConfig.resolve = {
    ...webpackConfig.resolve,
    tsConfigPath: ...
  }

2、module - JavaScript 資源

rspack 的每個 rule 配置必須指明他的 type ,如:

module: {
  rules: [
    {
      test: /\.tsx$/,
      // 🟢
      type: "tsx",
    },
  ];
}

這和 webpack 中的 asset type 等相似,但 rspack 不光有自己獨有的 type 類型(比如 tsx 、ts 等),也支持 asset type (見下文)。

目前常用的 type 有:

請各取所需。

3、module - CSS 資源

由於 webpack 的 css 配置過於繁瑣,此處僅介紹重點:

// 獲取 postcss options
const postcssOptions = {
  plugins: [
    require(require.resolve("postcss-flexbugs-fixes")),
    // ...
  ],
};
在 `webpack` 的 `postcss-loader` 選項中,插件是可以傳遞路徑的,如僅傳遞 `require.resolve('postcss-flexbugs-fixes')` ,但傳遞實例也可以,但 `rspack` 只能傳遞實例。

4、module - Asset 靜態資源

和 webpack 配置方式一致,可正常使用 asset type 註明靜態資源:

  {
    test: /\.(png|jpe?g|gif|webp)(\?.*)?$/i,
    type: 'asset/resource'
  }

注意 svgr 需要額外設定 type: 'tsx' ,表示以 JavaScript 方式承接,否則將得到錯誤的靜態資源,另外,由於 svgr 在內部使用 babel 轉譯組件,將花費較長時間,可 fork 後修改爲 esbuild 轉譯加速,或一律將 .svg 作爲靜態資源輸出。

5、plugins - 非內置能力

目前 rspack 對 webpack 插件 hooks api 支持較少,大部分插件無法使用,可用經典插件如下:

對於 html-webpack-plugin 的平替,有兩個方式可選:

在遷移過程中,作者發現的不可用插件如下:

明確了哪些經典插件可以直接使用,哪些不可以後,我們距離完整補全 webpack 插件相同的能力還差一些,這些能力已在 rspack 中內置( builtins ),通過 builtins.xxx 方式配置。

6、plugins - 內置能力

builtins.define

// rspack config
  builtins: {
    define: {
      'process.env.SOME': JSON.stringify('value'),
      // ...
    }
  }

該能力可以平替 DefinePlugin 插件,傳值方式一致。

builtins.copy

該能力可以平替 copy-webpack-plugin ,大部分選項與 webpack 一致,但不完整,不支持 globOptions ,這意味着無法忽略某些文件不被拷貝,從而我們無法做到將 index.html 模板文件放到靜態資源目錄。

比如我們預期拷貝 public/* 到產物目錄,但 index.html 我們無法放到 public/index.html 裏,因爲不支持配置忽略就會造成多份相同資源 emit 衝突,解決方法是 html 模板只能放到項目根目錄

builtins.react

swc 的 react 開發時配置,如下配置即可:

  builtins: {
    react: {
      development: isDev,
      refresh: isDev,
      runtime: 'automatic'
    }
  }

builtins.bar

相當於 webpackbar 的替代,但打印容易錯位,同時 rspack 非常快,沒有必要展示進度條,不建議配置該選項。

builtins.html

內置的 html 能力,缺點是沒有提供 HtmlWebpackPlugin 插件實例,無法和其他插件聯動,同時配置項不夠完整。

值得慶幸的是 lodash template 語法無論是 builtins.html 還是 @rspack/plugin-html 均支持,如 <%= htmlWebpackPlugin.options.title %> 。

若你需支持類似 CRA 的 %PUBLIC_URL% 變量替換,請使用 react-dev-utils/InterpolateHtmlPlugin 搭配 @rspack/plugin-html ,使用方式見 CRA eject 結果。

7、plugins - 其他

到這裏,如果嚴格和 webpack 插件相比,我們還缺少一些,比如 MiniCssExtractPlugin 、ReactRefreshWebpackPlugin 、ProvidePlugin ,這些由 rspack 內置支持,我們無需配置。

當你需要更多功能時,請優先尋找平替,他可能是一個 builtins.xxx 內置能力,或是某個選項,或是某個 @rspack/plugin-xxx 包。

8、optimization

對於 optimization.minimize 兩者一致。

對於 optimization.minimizer ,我們無需外部提供壓縮能力,已經內置。

對於 optimization.splitChunks ,目前支持的分包選項不夠全面,不支持調用函數(如 name() 、test() 等),此處推薦手動使用 webpack 拆包語法分包( () => import() );可以嘗試配置非函數選項,但是否生效未知。

9、cache

雖然 rspack 有 cache 選項,但截止本文發稿時,只能配置 true / false ,並未發現有緩存出現。

由於截止本文發稿時,rspack 暫未開源文檔未釋出,請後續自行探索。

10、其他

經作者探索,將某個 JavaScript 對象傳遞至 webpack 構建流程中,是可以通過引用的方式雙向同步數據的,但在 rspack 不可以,推測這與 Rust 不支持有關。

總結

本文介紹了 webpack 遷移至 rspack 的基本流程和相關探索,至此,已經完成了 CRA 所有基本能力的平替,代碼詳見 xn-sakina / xn 。

在作者嘗試開發過程中,熱更新仍存在丟失樣式等問題,經刷新頁面後恢復,請酌情采用(如開發時 rspack 構建時 webpack)。

關於更多 rspack 能力,請自行探索開源後的文檔的選項。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/1oa4HQFwfD7nVHxB0bcadg