Closed5

Webpack -> Rspack, Babel -> SWC 移行の覚え書き

つねみ@tocomiつねみ@tocomi

移行するうえで調べたこと、わかったことをまとめる

(弊社内で開発している Web アプリの webpack.config.js の設定を前提)

つねみ@tocomiつねみ@tocomi

現状の Babel が何をしているのか

plugin

lodash

https://github.com/lodash/babel-plugin-lodash

lodash 周りのツリーシェイキングをしてくれる。
ということはこの plugin の ON/OFF を比較するとバンドルサイズが変わるはず。
production ビルドされたファイルを比べてみると想定通りサイズに差分が出た。

plugin なし plugin あり
3,816 KB 3,751 KB

styled-components

https://styled-components.com/docs/tooling#babel-plugin

手元の設定では、以下のようになっていた。

{
  pure: true,
  ssr: false,
}

pure: DCE(Dead Code Elimination) をしやすくするオプション。
ssr: すべての styled component に一意な ID を追加することで、クライアントサイドとサーバーサイドで別々のクラス名が付与されてチェックサムが不一致になるのを防ぐ。今回のアプリは SPA なので false。

これも pure の true/false でバンドルサイズが変わることが予想される。
実際には、予想に反してバンドルサイズは一切変わらなかった。
あくまで DCE を補助するためのオプションだから、そもそも DCE の対象になるコードが存在しなかったということなのかな🤔

react-refresh/babel

https://github.com/pmmmwh/react-refresh-webpack-plugin

React アプリの開発中に HMR を有効をするためのライブラリの設定

presets

@babel/preset-react

jsx を js に変換するのに必要なやつ(多分)

@babel/preset-typescript

ts を js に変換するのに必要なやつ(多分)

@babel/preset-env

babel の基本的な設定が含まれたもの(多分)
手元の設定では以下を指定していた。

  • corejs: ポリフィルに利用する corejs のバージョンを指定
  • target: サポートするブラウザとバージョンを指定
  • usage: ポリフィルの注入方法の指定
つねみ@tocomiつねみ@tocomi

Webpack -> Rspack の検証

移行

https://rspack.dev/guide/migration/webpack

migration guide をもとに、Rspack を使って動く状態にすることは意外と簡単にできた🥳
さすが Webpack との互換を謳っているだけはあるなと思った。

変更点

Webpack Rspack
import * as webpack from 'webpack' import * as rspack from '@rspack/core'
CopyWebpackPlugin rspack.CopyRspackPlugin
webpack.DefinePlugin rspack.DefinePlugin
import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin' import ReactRefreshPlugin from '@rspack/plugin-react-refresh'
TsconfigPathsPlugin tsConfig(resolve のプロパティ)

成果物の差分は?

production ビルドでは、バンドルサイズは Rspack のほうが微増という感じ。

Webpack Rspack
3,751 KB 3,758 KB

差分は development ビルドで確認してみる。
refresh のプラグインが変わったことで、そのコード部分でアウトプットに差分が出ていることがわかった。
コード本体のロジック部分には差分はなさそうだった(全部はちゃんと見てないけど)

つねみ@tocomiつねみ@tocomi

Babel -> SWC の検証

移行

https://rspack.dev/guide/migration/webpack#babel-loader--swc-loader--builtinswc-loader

こちらも migration guide を参考に進める。
サンプルコードの SWC の設定を持ってくれば、

  • @babel/preset-react
  • @babel/preset-typescript
  • react-refresh/babel

の対応はできているように見えたので、残りの

  • @babel/preset-env
  • lodash-plugin
  • styled-components-plugin

の設定をオプトインしていく形で進めてみる。

@rspack/core から SwcLoaderOptions という型が export されているのでこれを使うと設定が楽。

{
  test: [/\.tsx?$/],
  exclude: [/[\\/]node_modules[\\/]/],
  loader: 'builtin:swc-loader',
  options: {
    /* some settings */
  } satisfies SwcLoaderOptions
}

@babel/preset-env

swc-loader の options.env に設定箇所があった。
@babel/preset-env に指定されていた設定値を移行。
targets が object ではなく string での指定になっていた。

env: {
  coreJs: 'core js version',
  mode: 'usage',
  targets: 'Chrome >= XX, Edge >= XX',
},

lodash-plugin

https://www.npmjs.com/package/@swc/plugin-transform-imports

lodash 用のなにかは見つからなかったが、swc 公式の plugins にある transform-imports を使うことで lodash の TreeShaking ができそう。
結果として plugin を入れることでバンドルサイズの減少が確認できた。

plugin なし plugin あり
3,820 KB 3,757 KB

styled-components-plugin

https://styled-components.com/docs/tooling#swc-plugin

SWC 用の plugin も提供されていたのでこちらを利用。
設定値をそのまま移行した。

成果物の差分

Rspack + Babel Rspack + SWC
3,758 KB 3,757 KB

結果として移行前後でほぼ成果物のサイズは変わらなかった。

つねみ@tocomiつねみ@tocomi

最終的な成果物

バンドルサイズは微増。
ビルド時間は大幅に短縮という結果になった。
早くなりすぎてビビる😂

バンドルサイズ

Webpack + Babel Rspack + SWC
3,751 KB 3,758 KB

ビルド時間

(5 回試行した際の平均値)

Webpack + Babel Rspack + SWC
devServer 起動 28.72s 3.20s
production build 42.39s 5.44s
HMR 1.83 s 0.49s
このスクラップは2024/09/08にクローズされました