Webpack→Viteに乗り換える際の速度面の変化の確認
概要
WebpackからViteに乗り換える際の影響について、どんな作業が必要だったか、 速度面ではどの程度変化したかをまとめる。
しばらく前に行った作業なので手順は過去に遡って確認する形になる。
Viteに乗り換える動機
Viteに乗り換えたくなった動機は以下のようなものだった。
- (1). webpack-dev-serverを使ったHMRで、初回のビルドが4分くらい掛かる
- (2). ソースコードを変更した後の2回目以降のビルドも2~3秒程度掛かる
- ESLintによるファイル保存時の自動fixも行っているため(?)このビルドが1回の保存につき2回以上発生する
- (3). webpack-dev-serverを起動し続けていると本来エラーはないはずなのにビルドエラーになってしまうケースがある
- 具体的なケースを特定できていないものの、PRレビューのためにブランチを切り替えて多数ファイルが切り替わる時はそれなりの頻度で発生する。
- webpack-dev-serverを再起動すると解消するものの、そのたびに(1)の時間が掛かる問題が気になる
どんな状態でWebpackを使用していたか
Vueを勉強不足なまま始めた頃のソースコードが残っていたり、CSSについても反省する部分が多い状態。
- ソースコードの状況
- JS(テストコード除く)
- ファイル数: 580
- 別途lodashを全体取り込んでしまってたりする
- ファイルサイズ: 460KB
- ファイル数: 580
- CSS (SCSS)
- ファイル数: 50
- 別途Bootstrapも取り込んでいる
- ファイルサイズ: 325KB
- ファイル数: 50
- JS(テストコード除く)
Webpackのプロファイリング
Viteに乗り換える以外に、未使用のコードの削除等で時間が短縮出来たのかも確認したいと思った。
具体的に今どの部分で重いのかをつかむため、webpackのTree Shakingを理解して不要なコードがバンドルされるのを防ぐを参考にWebpackの以下のプラグインを試してみた。
webpack-bundle-analyzer
- 古い頃のバンドルがとても大きな容量(20MB超)を占めていて、それはバンドルのJSファイルを見ても分かっていた
- 内容としてはstyleタグ内のSCSSが3MBくらい占めているものが複数含まれていて、見直しの余地がありそう
- Vuetifyはtreeshakingしていなかったのでしないと。
- lodashは一部のバンドルでは選択的に取り込むようにしていたはずが、全体が取り込まれてしまっている...?
speed-measure-webpack-plugin
こちらは実行して以下のような結果が得られたものの、具体的にどこが重いのかは把握できなかった。
(出力内容の意味をしっかり理解できなかった)
General output time took 4 mins, 41.21 secs
SMP ⏱ Plugins
BundleAnalyzerPlugin took 19.55 secs
SMP ⏱ Loaders
vue-loader, and
babel-loader, and
ts-loader, and
vue-loader took 3 mins, 36.87 secs
module count = 212
/home/xxxxx/projects/du/node_modules/laravel-mix/node_modules/babel-loader/lib/index.js??clonedRuleSet-5[0].rules[0].use[0]!/home/xxxxx/projects/xxxxxxx/node_modules/ts-loader/index.js??clonedRuleSet-6[0].rules[0]!/home/xxxxxxx/projects/xxxxxx/node_modules/vue-loader/lib/index.js??vue-loader-options!/home/xxxxx/projects/xxxxx/resources/js/xxxxxx/pages/xxxxxx/xxxxxxxxxx.vue?vue&type=script&lang=ts& = 53.45 secs
... (以下省略)
実際には上記のような「xxx-loader, and vueloader took X min」という記述が繰り返し出力されていて、単純に合計すると簡単に4分を突破してしまう。
おそらく並行処理しているとしても、どこで時間が掛かっているかパッとわからなそう...。
オレンジ色の部分のコードには古く使われていないものも含まれている(ただし整理は出来ておらず削除してよいか判断が難しい)ので、試しにバッサリ削除してみたけどビルド時間もバンドルのサイズも大して変わらなかった...。
実際に使っている部分でこれだけ占めてしまっている模様...。
今回はLaravelMixを通してWebpackを使用していて、上記プラグインを使うためにyarn add の他以下の設定を行った。
webpack.mix.js
+ const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin
+ const SpeedMeasurePlugin = require("speed-measure-webpack-plugin")
+ const smp = new SpeedMeasurePlugin({
+ humanVerbose: true,
+ outputTarget: "./speed-measure-plugin.json",
+ loaderTopFiles: 10,
+ })
mix.ts ( // ...中略
- mix.webpackConfig({
+ mix.webpackConfig(smp.wrap({
// ...中略
+ plugins: [new BundleAnalyzerPlugin()],
- }).sourceMaps()
+ })).sourceMaps()
Viteに切り替えたことによる、HMRの処理時間の確認
Viteに切り替えたことで、開発時のビルドに掛かる時間はほぼなくなり、
yarn dev
でHMRを開始した後の初回アクセスが重くなったと感じるものの、
その後は快適と思える状態になった。
(まだ大きな改修等は行っていないので、多数のファイルが変更されるブランチ切り替えを行った時どうなるかは未確認)
開発時のビルドに掛かる時間(yarn dev等の後の時間)は4分→ ほぼゼロになった 4.5秒程度になったものの、
初回アクセス時のみ時間が掛かると感じたため以下のような形でページアクセス時の時間を確認した。
検証方法
以下のような方法で2回実施
- Webpack版、またはVite版のブランチをcheckoutする
- yarn installを実行
- 以下のコマンドでHMRを開始
- Webpack: yarn hot
- Vite: yarn dev
- Chromeのシークレットモードを使用してページにアクセス(またはリロード)
- Chrome DevToolのNetworkタブでロード時間を確認
- ブランチを切り替えて最初の手順に戻る
結果
初回アクセス時は重く感じるものの、それ以外ではほとんど差がない状態。
(以下は太字の方が遅い)
WebPack
DomContentLoaded | Loaded | Finished | |
---|---|---|---|
初回のロード時間: | 1.43 | 1.96 | 3.35 |
2回目以降(通常のロード): | 1.21 | 1.71 | 3.05 |
2回目以降(スーパーリロード): | 1.43 | 2.03 | 3.28 |
Vite
DomContentLoaded | Loaded | Finished | |
---|---|---|---|
初回のロード時間: | 1.84 | 3.15 | 5.78 |
2回目以降(通常のロード): | 1.09 | 1.30 | 2.92 |
2回目以降(スーパーリロード): | 1.40 | 1.56 | 3.19 |
当初「ほぼゼロになった」と書いていたが、node_modules/.vite 配下に依存関係をesbuildでビルドしたものがキャッシュされていた。
これを削除して yarn dev
を実行するのを2回確認したところ、 およそ4.5秒だった。
本番ビルドの処理時間の比較
Viteの本番ビルドはバンドルが発生するため処理時間がないわけではないので、Webpackのビルドと比較する(こちらも交互に2回確認。Viteはキャッシュをクリア)。
バンドラー | 処理時間 | 備考 |
---|---|---|
Webpack | 280.97 | |
Vite | 44.26 | モジュール数は2,709 |
Viteの本番ビルドは、vite-cliだと vue-tsc --noEmit
も実行するようになっているものの、
これを実行すると現時点では多数のエラーが挙がってしまい実行していない状態。
(せめて @ts-expect-error
で対処した方が良いと思う...)
ビルド後のアセットのサイズの比較
ビルド後のアセットのサイズにもだいぶ差があった。
かなり顕著な差なので、自分がWebpackを勉強不足でこうなってしまっているかもしれない。
(どちらもソースマップを含めた状態)
バンドラー | サイズ |
---|---|
Webpack | 63MB |
Vite | 21MB |