Webpack -> Rspack, Babel -> SWC 移行の覚え書き
移行するうえで調べたこと、わかったことをまとめる
(弊社内で開発している Web アプリの webpack.config.js の設定を前提)
現状の Babel が何をしているのか
plugin
lodash
lodash 周りのツリーシェイキングをしてくれる。
ということはこの plugin の ON/OFF を比較するとバンドルサイズが変わるはず。
production ビルドされたファイルを比べてみると想定通りサイズに差分が出た。
plugin なし | plugin あり |
---|---|
3,816 KB | 3,751 KB |
styled-components
手元の設定では、以下のようになっていた。
{
pure: true,
ssr: false,
}
pure: DCE(Dead Code Elimination) をしやすくするオプション。
ssr: すべての styled component に一意な ID を追加することで、クライアントサイドとサーバーサイドで別々のクラス名が付与されてチェックサムが不一致になるのを防ぐ。今回のアプリは SPA なので false。
これも pure の true/false でバンドルサイズが変わることが予想される。
実際には、予想に反してバンドルサイズは一切変わらなかった。
あくまで DCE を補助するためのオプションだから、そもそも DCE の対象になるコードが存在しなかったということなのかな🤔
react-refresh/babel
React アプリの開発中に HMR を有効をするためのライブラリの設定
presets
@babel/preset-react
jsx を js に変換するのに必要なやつ(多分)
@babel/preset-typescript
ts を js に変換するのに必要なやつ(多分)
@babel/preset-env
babel の基本的な設定が含まれたもの(多分)
手元の設定では以下を指定していた。
- corejs: ポリフィルに利用する corejs のバージョンを指定
- target: サポートするブラウザとバージョンを指定
- usage: ポリフィルの注入方法の指定
Webpack -> Rspack の検証
移行
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 のプラグインが変わったことで、そのコード部分でアウトプットに差分が出ていることがわかった。
コード本体のロジック部分には差分はなさそうだった(全部はちゃんと見てないけど)
Babel -> SWC の検証
移行
こちらも 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
lodash 用のなにかは見つからなかったが、swc 公式の plugins にある transform-imports を使うことで lodash の TreeShaking ができそう。
結果として plugin を入れることでバンドルサイズの減少が確認できた。
plugin なし | plugin あり |
---|---|
3,820 KB | 3,757 KB |
styled-components-plugin
SWC 用の plugin も提供されていたのでこちらを利用。
設定値をそのまま移行した。
成果物の差分
Rspack + Babel | Rspack + SWC |
---|---|
3,758 KB | 3,757 KB |
結果として移行前後でほぼ成果物のサイズは変わらなかった。
最終的な成果物
バンドルサイズは微増。
ビルド時間は大幅に短縮という結果になった。
早くなりすぎてビビる😂
バンドルサイズ
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 |