webpackからviteへの移行で開発速度を改善する実装手順

きっかけ・動機

社内で運用しているLPテンプレートは、HTML、SCSS、JavaScriptで構成されていました。ビルドツールとしてwebpackを使っていたのですが、開発中のビルド時間が30秒近くかかっていて、ちょっとした修正を確認するだけでも待たされていました。そのたびに開発のテンポが落ちるのを感じていました。

より速い開発体験を求めて、viteへの移行を検討することにしました。

環境と前提

移行時の環境を記載しておきます。

  • OS:Linux(開発チーム全員同じ環境を使用)
  • Node.js:18.x以上
  • ビルドツール:webpack 5 → vite 4(現在は5系も利用可能)
  • テンプレート構成:複数のHTML、SCSS、JavaScriptファイル
  • 参考にした資料:vite公式ドキュメント、webpack→vite移行ガイド

やったこと

基本的なviteセットアップ

まずはviteをプロジェクトに導入しました。npm経由でインストール後、基本的な設定ファイルvite.config.jsを作成します。webpackと比べて、デフォルトの設定がシンプルなのが特徴です。

PowerShell
npm install -D vite

基本的なvite.config.jsの例です。

JavaScript
import { defineConfig } from 'vite'

export default defineConfig({
  server: {
    port: 3000,
    open: true
  }
})

複数エントリポイントの設定

LPテンプレートではファイル構成上、複数のHTMLファイルをエントリポイントとして扱う必要がありました。ここが設定の工夫が必要だった部分です。

viteのローリング形式は単一エントリ向けが基本のため、複数のHTMLを処理するにはglobを使って動的にエントリを指定します。

JavaScript
import { defineConfig } from 'vite'
import { glob } from 'glob'
import path from 'path'

export default defineConfig({
  build: {
    rollupOptions: {
      input: Object.fromEntries(
        glob.sync('src/pages/**/*.html').map(file => [
          path.relative('src', file.slice(0, file.length - path.extname(file).length)),
          path.resolve(__dirname, file)
        ])
      )
    }
  }
})

このapproachにより、src/pages/ディレクトリ配下のすべてのHTMLを自動的にエントリとして認識します。

SCSSの設定

SCSSサポートはviteで標準搭載されているので、別途ローダーは不要です。ただしSCSSパーシャルの解決で工夫が必要でした。

vite.config.jsに以下を追加して、SCSSの検索パスを明示します。

JavaScript
export default defineConfig({
  css: {
    preprocessorOptions: {
      scss: {
        includePaths: ['src/styles']
      }
    }
  }
})

これにより、src/styles配下のパーシャルを@importで参照する際に、相対パスではなく直接ファイル名で指定できるようになります。

画像パス処理

webpackでは画像をrequire()またはimportで明示的に読み込む習慣がありました。viteではこのアプローチが異なります。

HTMLファイル内で画像を参照する場合、相対パスを使って直接指定します。

HTML
<!-- HTML内での画像参照 -->
<img src="./assets/images/logo.png" alt="ロゴ">

JavaScriptで動的に画像を参照する場合はimport文で読み込みます。

JavaScript
import logoImage from './assets/images/logo.png'

document.querySelector('.header').style.backgroundImage = `url(${logoImage})`

publicディレクトリに置いた画像は、ビルド時に最適化対象外になり、ルートパスから参照できます。

つまずいた点

SCSSパーシャルの解決

最初、SCSSパーシャルをwebpackと同じ方法で参照していたのですが、エラーが出ました。@import_variables.scssを読み込もうとすると、「ファイルが見つからない」という警告が返ってきました。

原因は、webpackのsass-loaderでは自動的に特定のディレクトリを検索パスに含める設定があったのに対し、viteではそれを明示的に指定する必要があるからです。

前述のscss.includePathsを設定した後は問題が解決しました。移行時にscssキーがなかったため、SCSSの@importが機能していなかったわけです。

画像パス処理

webpackではrequire('./assets/images/logo.png')のように、JavaScriptから画像を読み込む習慣がありました。viteでもこの方法は可能ですが、HTMLテンプレート内での画像参照は仕様が変わります。

HTMLファイルで相対パスを直接指定すると、ビルド後に自動的にハッシュ付きのパスに書き換えられます。しかし開発時と本番時でパス解決の動作が微妙に異なる場合があったため、確認に時間がかかりました。

解決策として、画像が置かれるディレクトリ構造をビルド前後で統一し、開発サーバーで十分にテストしてから本番ビルドを実行することで、問題を回避できました。

結果・所感

移行後、開発中のビルド・リロード時間が大幅に改善されました。HTMLやSCSSを編集したときのホットモジュールリロード(HMR)が非常に速く、修正を確認するのに待ち時間がほぼなくなりました。

webpackの30秒近いビルド時間から、viteは初回ビルドで数秒、HMR対応の修正は1秒未満で反映されるようになったため、開発体験は大きく向上しました。

設定面では、webpackと比べてviteは最小限の設定で動作する点が気に入っています。複数エントリの設定も、最初こそglobの理解が必要でしたが、一度設定すれば以後は変更不要でした。

LPテンプレート以外のプロジェクトでも、同じ考え方で適用できそうだと感じました。

まとめ

webpackからviteへの移行は、複数エントリポイントとSCSSパーシャル、画像パスの3つのポイントを押さえることで実現できました。

特にSCSSパーシャルの解決と画像パス処理は、webpackからの習慣をそのまま持ち込むと引っかかりやすい箇所です。開発サーバーで十分に動作を確認してから本番ビルドに進むことをお勧めします。

viteのシンプルな設定と高速なHMRは、開発のテンポを大きく改善します。既存プロジェクトの移行に前向きに検討する価値があります。

参考リンク

read next