🌟

【コーダー向け】webpackでEJS・Sass・JSな普通のコーディング環境を作ってみた

2022/07/16に公開約23,300字

モダン開発ではないWebサイトコーディング用のwebpack環境を作った備忘録です。

webpackの情報は沢山出回っていますが、自分の制作環境と完全一致するものが見つけられなかったので一度自作してみることにしました。

先に構築内容をまとめて記載しています。
後半は内容の補足などです。

初期設定(ファイルのインストール)

・構築したいディレクトリへ移動

作業を始める前に設定したいプロジェクトのあるディレクトリまで移動してください。

Windowsでの移動

cd C:¥Users¥.....¥webpackを構築したいプロジェクトディレクトリ

Macでの移動

cd /Users/....../webpackを構築したいプロジェクトディレクトリ

・package.jsonを作成

以下のコマンドを実行してpackage.jsonを作成します。

npm init -y 

・webpackをインストール

以下のコマンドを実行してwebpackのベースファイル一式をインストールします。

npm install -D webpack webpack-cli webpack-dev-server

・babelプラグインをインストール

以下のコマンドを実行してbabelプラグイン一式をインストールします。

npm install -D @babel/core @babel/preset-env babel-loader

・ファイル分割プラグインをインストール

以下のコマンドを実行してファイル分割に利用するプラグインをインストールします。

npm install -D webpack-watched-glob-entries-plugin

・ファイルコピープラグインをインストール

以下のコマンドを実行してファイルコピープラグインをインストールします。

npm install -D copy-webpack-plugin

・EJSプラグインをインストール

以下のコマンドを実行してEJSプラグイン一式をインストールします。

npm install -D html-webpack-plugin html-loader template-ejs-loader

・Sassプラグインをインストール

以下のコマンドを実行してSassプラグイン一式をインストールします。

npm install -D css-loader sass-loader sass mini-css-extract-plugin

・PostCSSプラグインをインストール

以下のコマンドを実行してPostCSSプラグイン一式をインストールします。

npm install -D postcss postcss-loader autoprefixer postcss-sort-media-queries css-declaration-sorter @fullhuman/postcss-purgecss postcss-normalize-charset

━ browserslistの設定(autoprefixerの設定)

autoprefixerを追加した場合は、
package.jsonに対象となるブラウザ範囲"browserslist"を追記してください。

package.json
{
  〜省略〜
  "devDependencies": {
   〜省略〜
  },
  "browserslist": [
    "last 3 versions",
    "> 5%",
    "iOS >= 9.0",
    "Android >= 5",
    "Firefox ESR"
  ]
}

browserslistは環境に合わせて適宜変更してください。
設定の詳細は以下をご参照ください。

https://github.com/browserslist/browserslist#queries

Sassファイルの読み込み

src/js/ に内包するメインのjsファイル(任意の名称)にSassファイルをimportする記述を追加します。

src/js/[任意の名称].js
import "../sass/style.scss";

webpackの設定用JSファイルを作成

開発ディレクトリに3つのJSファイル(webpack.common.js、webpack.dev.js、webpack.prod.js)を作成します。

・webpack.common.js (ベース設定ファイル)

webpack.common.js
/*
  webpack.dev.js、webpack.prod.jsへビルド設定を渡す
  引数[MODE]は webpack の出力オプション('production' か 'development')を指定します
*/
const webpackConfig = (MODE) => {

  //purgecssの除外設定
  const cssSafeList = ['hoge'];

  //ベースファイルのパス設定
  const filePath = {
    js: './src/js/',
    ejs: './src/ejs/',
    sass: './src/sass/',
  };

  // ソースマップの利用有無判別(productionのときはソースマップを利用しない)
  const enabledSourceMap = MODE === "development";


  //ベース設定読み込み
  const path = require("path");
  const MiniCssExtractPlugin = require("mini-css-extract-plugin");
  const CopyPlugin = require("copy-webpack-plugin");
  const WebpackWatchedGlobEntries = require("webpack-watched-glob-entries-plugin");


  //sassファイル分割
  const entriesScss = WebpackWatchedGlobEntries.getEntries([path.resolve(__dirname, `${filePath.sass}**/**.scss`)], {
    ignore: path.resolve(__dirname, `${filePath.sass}**/_*.scss`),
  })();
  const cssGlobPlugins = (entriesScss) => {
    return Object.keys(entriesScss).map(key => new MiniCssExtractPlugin({
        //出力ファイル名
        filename: `assets/css/${key}.css`
      })
    );
  };


  //jsファイル分割
  const entriesJS = WebpackWatchedGlobEntries.getEntries([path.resolve(__dirname, `${filePath.js}*.js`)])();


  //ejsビルド
  const entries = WebpackWatchedGlobEntries.getEntries([path.resolve(__dirname, `${filePath.ejs}**/*.ejs`)], {
    ignore: path.resolve(__dirname, `${filePath.ejs}**/_*.ejs`),
  })();
  const HtmlWebpackPlugin = require("html-webpack-plugin");
  const { htmlWebpackPluginTemplateCustomizer } = require("template-ejs-loader");
  const htmlGlobPlugins = (entries) => {
    return Object.keys(entries).map(key => new HtmlWebpackPlugin({
        //出力ファイル名
        filename: `${key}.html`,
        //ejsファイルの読み込み
        template: htmlWebpackPluginTemplateCustomizer({
          htmlLoaderOption: {
            //ファイル自動読み込みと圧縮を無効化
            sources: false,
            minimize: false
          },
          templatePath: `${filePath.ejs}${key}.ejs`,
        }),

        //JS・CSS自動出力と圧縮を無効化
        inject: false,
        minify: false,
      })
    );
  };

  //ビルド設定を各jsファイルへ渡す
  return {
    // モード値を production に設定すると最適化された状態で、
    // development に設定するとソースマップ有効でJSファイルが出力される
    mode: MODE,

    // ローカル開発用環境を立ち上げる
    // 実行時にブラウザが自動的に localhost を開く
    devServer: {
      hot: true, //ホットリロードを有効化(変更された部分のみを更新)
      static: path.resolve(__dirname, 'src'),
      open: true
    },
    target: 'web', //ローカルサーバのリロードを有効化する

    //JS書き出しファイル読み込み
    entry: entriesJS,

    //JS書き出し設定
    output: {
      path: path.resolve(__dirname, 'dist'),
      filename: 'assets/js/[name].js',
      clean: true, //ビルド時にdistフォルダをクリーンアップする
    },

    module: {
      rules: [
        //ejs
        {
          test: /\.ejs$/i,
          use: ['html-loader','template-ejs-loader']
        },

        //babel-loader
        {
          // 拡張子 .js の場合
          test: /\.js$/,
          exclude: /node_modules/,
          use: [
            {
              // Babel を利用する
              loader: "babel-loader",
              // Babel のオプションを指定する
              options: {
                presets: [
                  ['@babel/preset-env', { targets: "defaults" }]
                ],
              },
            },
          ],
        },

        //Sass
        {
          test: /\.scss/, // 対象となるファイルの拡張子
          use: [
            // CSSファイルを書き出すオプションを有効にする
            {
              loader: MiniCssExtractPlugin.loader,
            },
            {
              loader: "css-loader",
              options: {
                // オプションでCSS内のurl()メソッドの取り込みを禁止する
                url: true,
                // ソースマップの利用有無
                sourceMap: enabledSourceMap,

                // Sass+PostCSSの場合は2を指定
                // 0 => no loaders (default);
                // 1 => postcss-loader;
                // 2 => postcss-loader, sass-loader
                importLoaders: 2
              }
            },
            // PostCSSのための設定
            {
              loader: "postcss-loader",
              options: {
                // PostCSS側でもソースマップを有効にする
                // sourceMap: true,
                postcssOptions: {
                  plugins: [
                    ['postcss-normalize-charset', {},],
                    ['autoprefixer', {}],
                    ['postcss-sort-media-queries', {}],
                    ['css-declaration-sorter', {order:'smacss'}],
                    [
                      '@fullhuman/postcss-purgecss',
                      {
                        //purgecssオプション:ejsファイルとjsファイルを監視対象にする
                        content: [`${filePath.ejs}**/*.ejs`,`${filePath.js}**/*.js`],
                        //purgecssオプション:除外設定 https://purgecss.com/safelisting.html
                        safelist: cssSafeList //除外要素は8行目で設定
                      }
                    ]

                  ],
                },
              },
            },
            {
              loader: "sass-loader",
              options: {
                // ソースマップの利用有無
                sourceMap: enabledSourceMap
              },
            },
          ],
        },

        //CSS内の画像読み込み設定
        {
          test: /\.(gif|png|jpg|svg)$/,
          // 閾値以上だったら埋め込まずファイルとして分離する
          type: "asset",
          parser: {
            dataUrlCondition: {
              // 4KB以上だったら埋め込まずファイルとして分離する
              maxSize: 4 * 1024,
            },
          },
          //書き出し設定
          generator: {
            filename: 'assets/images/[name][ext]'
          }
        },
	
        //CSS内のWebfont読み込み設定
        {
          test: /\.(ttf|otf|eot|woff|woff2)$/,
          // 閾値以上だったら埋め込まずファイルとして分離する
          type: "asset",
          parser: {
            dataUrlCondition: {
              // 4KB以上だったら埋め込まずファイルとして分離する
              maxSize: 4 * 1024,
            },
          },
          //書き出し設定
          generator: {
            filename: 'assets/fonts/[name][ext]'
          }
        },

      ],
    },

    plugins: [
      // CSS出力
      ...cssGlobPlugins(entriesScss),

      // ejs出力
      ...htmlGlobPlugins(entries),

      //ディレクトリコピー
      new CopyPlugin({
        patterns: [
          //画像コピー
          {
            from: path.resolve(__dirname, 'src/images/'),
            to: path.resolve(__dirname, 'dist/assets/images'),
          },
        ],
      }),
    ],
  };
}
module.exports = { webpackConfig };

・webpack.dev.js (開発用設定ファイル)

webpack.dev.js
//webpack.common.jsを読み込み'development'設定で出力
const { webpackConfig } = require('./webpack.common');
module.exports = webpackConfig('development');

・webpack.prod.js (ビルド用設定ファイル)

webpack.prod.js
//webpack.common.jsを読み込み'production'設定で出力
const { webpackConfig } = require('./webpack.common');
module.exports = webpackConfig('production');

package.jsonへコマンドを追加

package.jsonへ各コマンドを追加します

package.json
{
  〜省略〜
  "scripts": {
    "build": "webpack --config webpack.prod.js",
    "dev": "webpack serve --config webpack.dev.js",
    "watch": "webpack --watch --config webpack.dev.js"
  },
  〜省略〜
}

・ビルドコマンド

npm run buildでファイル一式が書き出されます。

npm run build

・開発コマンド

npm run devでローカルサーバーが立ち上がり開発を開始できます。

npm run dev

・差分ビルドコマンド

npm run watchでファイルの差分ビルドを開始できます。

npm run watch

・package.json

package.json
{
  "name": "プロジェクト名",
  "version": "1.0.0",
  "description": "",
  "main": "webpack.config.js",
  "scripts": {
    "build": "webpack --config webpack.prod.js",
    "dev": "webpack serve --config webpack.dev.js",
    "watch": "webpack --watch --config webpack.dev.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.18.6",
    "@babel/preset-env": "^7.18.6",
    "@fullhuman/postcss-purgecss": "^4.1.3",
    "autoprefixer": "^10.4.7",
    "babel-loader": "^8.2.5",
    "copy-webpack-plugin": "^11.0.0",
    "css-declaration-sorter": "^6.3.0",
    "css-loader": "^6.7.1",
    "html-loader": "^4.1.0",
    "html-webpack-plugin": "^5.5.0",
    "mini-css-extract-plugin": "^2.6.1",
    "postcss": "^8.4.14",
    "postcss-loader": "^7.0.1",
    "postcss-normalize-charset": "^5.1.0",
    "postcss-sort-media-queries": "^4.2.1",
    "sass": "^1.53.0",
    "sass-loader": "^13.0.2",
    "template-ejs-loader": "^0.9.3",
    "webpack": "^5.73.0",
    "webpack-cli": "^4.10.0",
    "webpack-dev-server": "^4.9.3",
    "webpack-merge": "^5.8.0",
    "webpack-watched-glob-entries-plugin": "^2.2.4"
  }
}

ディレクトリ構成

開発ファイルを src/で管理する構成です。

■プロジェクトディレクトリ
 ┣ dist (ビルドしたファイルが出力される場所)
 ┣ package.json (プロジェクトのjsonファイル)
 ┣ webpack.common.js (webpackの設定ファイル(ベース))
 ┣ webpack.dev.js (webpackの設定ファイル(開発用))
 ┣ webpack.prod.js (webpackの設定ファイル(ビルド用))
 ┣ .jsbeautifyrc (任意:HTML整形プラグインjs-beautifyの設定ファイル)
 ┃
 ┣ node_modules (編集不要:自動生成されるコアファイル格納場所)
 ┣ package-lock.json (編集不要:インストールしたパッケージ情報などが記載されている)
 ┃
 ┗ src
    ┣ ejs
    ┣ json (ejsで利用するjsonファイルを格納)
    ┣ js
    ┣ images
    ┗ scss

経緯など

今度実務で開発環境一式も納品する必要が出てきました。
前回の記事で取り上げたViteでも良いかなと思ったのですが、先方がどんな条件でコーディングするか不明だったり、そもそもViteに対する自分の知識が浅いため、何かイレギュラーが起きた時に対応が難しいと判断し導入を見送りました。

何が良いか考えた結果、今回は一般的に広く使われていて情報が多そうなwebpackで納品することに決めました。
(長年使って慣れているGulpは先方が編集している時にも監視を無視するいけずが出るかもしれないので却下しました。)

そこから色々調べたのですが、なかなか自分の環境にハマるものが見つけられなかったので、一度自分でちゃんと構築してみることにしました。

この記事のwebpackでできること

  • 複数のJSファイルを生成
  • EJSで複数のHTMLファイルを生成
  • ビルド後のHTMLファイルを整形(任意追加)
  • Sassをビルドして複数のCSSファイルを生成
  • CSSファイルで読み込んでいる画像のうち、指定サイズ以下のものはbase64に変換して埋め込む
  • PostCSSによるオプション設定
    • autoprefixer:ベンダープレフィックスの追加
    • postcss-sort-media-queries:メディアクエリをソートして1つにまとめる
    • css-declaration-sorter:プロパティ順のソート(smacss)
    • postcss-purgecss:CSSファイルから未使用のスタイルを削除する
    • postcss-normalize-charset:先頭にcharset追加

EJS内でのファイル参照について

EJSファイル内のJSやCSSを自動挿入したり、自動的に画像などのファイルを参照する設定は無効化していますので、普通のコーディングと同じように手動で各ファイルを参照してください。

index.ejs
<!DOCTYPE html>
<html lang="ja">
<head>
  <link rel="stylesheet" href="./assets/css/style.css">
</head>
<body>
  <img src="./assets/images/hoge.jpg" alt="">

  <script src="./assets/js/fuga.js"></script>
</body>
</html>

JSONファイルの参照

require()を使うとJSONファイルからデータを引用することができます。
EJSファイルがある場所から相対パスで参照します。

━ JSファイルに更新パラメータを追加した例

src/json/data.json
{
  "param": "2022071601"
}
src/ejs/index.ejs
<body>
  <% const jsonData = require('../json/data.json') %>
  <script src="./assets/js/common.js?<%= jsonData.param %>"></script>
</body>
</html>

JSON以外にもJSファイルで作成したオブジェクトを参照することも可能です。
詳細は以下をご参照ください。

https://github.com/dc7290/template-ejs-loader/blob/main/docs/README-ja.md#-importing-javascript-or-json-files

js-beautifyでビルドしたHTMLを整形する(任意追加)

npm run build でビルドしたHTMLをnpm scriptsを用いて整形する設定です。
環境に合わせて適宜導入を検討してください。

・HTML整形プラグインjs-beautifyをインストール

以下のコマンドを実行してHTML整形プラグインをインストールします。

npm install -D js-beautify

━ .jsbeautifyrcのファイルを作成(js-beautifyの設定)

開発ディレクトリに.jsbeautifyrcを作成し、JSON形式でHTML整形のオプション設定を追加します。

.jsbeautifyrc
{
  "html": {
    "indent_size": 2,
    "unformatted": ["svg", "pre"]
  }
}

オプション設定は環境に合わせて適宜変更してください。
詳細は以下をご参照ください。

https://github.com/beautify-web/js-beautify#css--html

.jsbeautifyrcに追記する書き方は以下が参考になります。

https://gist.github.com/wzup/fc3254562236c1ec3f69#file-jsbeautifyrc-L17

━ package.jsonへコマンドを追加

package.jsonの "build" コマンドにjs-beautifyのコマンドを追記します。

package.json
{
  〜省略〜
  "scripts": {
    "build": "webpack --config webpack.prod.js && html-beautify dist/**/*.html",
    〜省略〜
  },
  〜省略〜
}

・実行方法

npm run buildを実行すると自動的に dist/ にあるHTMLファイルが整形されるようになります。

PostCssのオプション設定について

webpack.common.jsにオプション設定を記載しています。
各プラグインはpostcssOptions.pluginsで設定したものが呼び出されますので、不要なものは適宜削除してください。

webpack.common.js
const webpackConfig = (MODE) => {

  //purgecssの除外設定
  const cssSafeList = ['hoge'];

  〜省略〜

  //ビルド設定を各jsファイルへ渡す
  return {
    〜省略〜
    module: {
      rules: [
        〜省略〜
	
        //Sass
        {
          test: /\.scss/, // 対象となるファイルの拡張子
          use: [
	  
            〜省略〜
	    
            // PostCSSのための設定
            {
              loader: "postcss-loader",
              options: {
                // PostCSS側でもソースマップを有効にする
                // sourceMap: true,
                postcssOptions: {
                  plugins: [
                    ['postcss-normalize-charset', {},],
                    ['autoprefixer', {}],
                    ['postcss-sort-media-queries', {}],
                    ['css-declaration-sorter', {order:'smacss'}],
                    [
                      '@fullhuman/postcss-purgecss',
                      {
                        //purgecssオプション:ejsファイルとjsファイルを監視対象にする
                        content: [`${filePath.ejs}**/*.ejs`,`${filePath.js}**/*.js`],
                        //purgecssオプション:除外設定 https://purgecss.com/safelisting.html
                        safelist: cssSafeList //除外要素は8行目で設定
                      }
                    ]

                  ],
                },
              },
            },
            {
              loader: "sass-loader",
              options: {
                // ソースマップの利用有無
                sourceMap: enabledSourceMap
              },
            },
          ],
        },

        〜省略〜

      ],
    },

    plugins: [
      〜省略〜
    ],
  };
}
module.exports = { webpackConfig };

PostCssのプラグインについて

━ ベンダープレフィックスを追加するautoprefixer

https://www.npmjs.com/package/autoprefixer

━ メディアクエリをソートして1つにまとめる postcss-sort-media-queries

https://www.npmjs.com/package/postcss-sort-media-queries

━ CSSプロパティの順番をソートする css-declaration-sorter

https://www.npmjs.com/package/css-declaration-sorter

━ CSSファイルから未使用のスタイルを削除する postcss-purgecss

https://purgecss.com/plugins/postcss.html

━ CSSファイルの先頭にcharset追加する postcss-normalize-charset

https://www.npmjs.com/package/postcss-normalize-charset

CSSファイル内の画像読み込みについて(base64変換)

Sassファイル内で画像を読み込んだ時、4KB以下の画像だった場合はビルド時にbase64へ自動変換され画像が文字情報として埋め込まれます。

  • 4KB以下の画像:ビルド時にbase64へ自動変換し文字情報として埋め込まれる
  • 4KBを超える画像:imagesへ格納した画像をそのまま参照する

━ ビルド前に4KB以下の画像を参照している例

src/style.scss
.hoge {
  background-image: url(../images/piyo.svg);
}

━ base64に変換された例

dist/assets/css/style.css
.hoge {
  /* 4KB以下はbase64へ変換される */
  background-image: url(data:image/svg+xml;base64,xxx...);
}

・容量の基準値を変更する

容量の基準値はwebpack.common.jsのparser.dataUrlConditionで変更可能です。

webpack.common.js
const webpackConfig = (MODE) => {
  〜省略〜
  
  //ビルド設定を各jsファイルへ渡す
  return {
    〜省略〜

    module: {
      rules: [
        〜省略〜

        //CSS内の画像読み込み設定
        {
          test: /\.(gif|png|jpg|svg)$/,
          // 閾値以上だったら埋め込まずファイルとして分離する
          type: "asset",
          parser: {
            dataUrlCondition: {
              // 4KB以上だったら埋め込まずファイルとして分離する
              maxSize: 4 * 1024,
            },
          },
          //書き出し設定
          generator: {
            filename: 'assets/images/[name][ext]'
          }
        },

      ],
    },

    plugins: [
      〜省略〜
    ],
  };
}
module.exports = { webpackConfig };

@babel/preset-envのtargets設定について

IE11が死滅した昨今ES5への対応は不要と考え、@babel/preset-envの設定はひとまず defaults にしています。

targetsはautoprefixerと同じbrowserslistに順ずるようで、
defaultsは > 0.5%, last 2 versions, Firefox ESR, not dead とのことですので、モダン環境は問題ないように思いますが、記事執筆時点では未検証ですのでもし不具合など出るようなら各自の環境に合わせて対応範囲を変更してください。

webpack.common.js
const webpackConfig = (MODE) => {
  〜省略〜

  //ビルド設定を各jsファイルへ渡す
  return {
    〜省略〜

    module: {
      rules: [
        〜省略〜

        //babel-loader
        {
          // 拡張子 .js の場合
          test: /\.js$/,
          exclude: /node_modules/,
          use: [
            {
              // Babel を利用する
              loader: "babel-loader",
              // Babel のオプションを指定する
              options: {
                presets: [
                  ['@babel/preset-env', { targets: "defaults" }]
                ],
              },
            },
          ],
        },

        〜省略〜
      ],
    },

    plugins: [
      〜省略〜
    ],
  };
}
module.exports = { webpackConfig };

browserslistなど各内容の詳細は以下をご参照ください。

https://github.com/babel/babel-loader#usagebabel-loader

https://babeljs.io/docs/en/options#targets

https://github.com/browserslist/browserslist#queries

src/images/の移動について

ファイルコピープラグインcopy-webpack-pluginでnpm run build時に複製する仕様です。
他にもそのまま複製したいディレクトリがある場合は patternsオプションに任意の値を設定したオブジェクトを追加していってください。

webpack.common.js
/*
  webpack.dev.js、webpack.prod.jsへビルド設定を渡す
  引数[MODE]は webpack の出力オプション('production' か 'development')を指定します
*/
const webpackConfig = (MODE) => {
  〜省略〜
  const CopyPlugin = require("copy-webpack-plugin");
  
  〜省略〜

  //ビルド設定を各jsファイルへ渡す
  return {
    〜省略〜

    module: {
      〜省略〜
    },

    plugins: [
      〜省略〜

      //ディレクトリコピー
      new CopyPlugin({
        patterns: [
          //画像コピー
          {
            from: path.resolve(__dirname, 'src/images/'),
            to: path.resolve(__dirname, 'dist/assets/images'),
          },
        ],
      }),
    ],
  };
}
module.exports = { webpackConfig };

https://webpack.js.org/plugins/copy-webpack-plugin/

ビルド時にdistフォルダをクリーンアップする・しない

output.clean 設定を trueにすると npm run buildした時にdistフォルダをクリーンアップしてからファイルをビルドします。
クリーンアップしたくない場合は falseにするか、項目自体を削除してください。

webpack.common.js
const webpackConfig = (MODE) => {
  〜省略〜

  //ビルド設定を各jsファイルへ渡す
  return {
    〜省略〜
    
    //JS書き出し設定
    output: {
      path: path.resolve(__dirname, 'dist'),
      filename: 'assets/js/[name].js',
      clean: true, //ビルド時にdistフォルダをクリーンアップする
    },

    module: {
      〜省略〜
    },

    plugins: [
      〜省略〜
    ],
  };
}
module.exports = { webpackConfig };

ファイル分割の仕様について

ビルド時と開発時で出力オプション(productiondevelopment)を変更する時、毎回オプションを手動で書き換えるのは手間だったので調べてみると、ビルドと開発時でファイルを分割管理する方法がありました。

一般的にはwebpack-mergeプラグインを導入して対応しているようなのですが、これを設定するとModule not foundのエラーが出てしまいました。
おそらくエラーはresolveオプションなどで上手く解決するのだと思うのですが上手く解決できなかったため導入を見送りました。

結局出力オプションの分岐は自作関数で対処したので、他の記事とはベース構造が若干異なっていると思います。

https://www.npmjs.com/package/webpack-merge

ローカル開発環境(localhost)のホットリロードオプションについて

ホットリロードは、ページ全体をリロードせずファイルの変更部分だけ更新する方法です。
devServer.hot オプションを有効化するとホットリロードされるようになります。

webpack.common.js
const webpackConfig = (MODE) => {
  〜省略〜
  
  //ビルド設定を各jsファイルへ渡す
  return {
    〜省略〜
    
    // ローカル開発用環境を立ち上げる
    // 実行時にブラウザが自動的に localhost を開く
    devServer: {
      hot: true, //ホットリロードを有効化(変更された部分のみを更新)
      static: path.resolve(__dirname, 'src'),
      open: true
    },
    target: 'web', //ローカルサーバのリロードを有効化する
    
    〜省略〜
    
    module: {
      〜省略〜
    },

    plugins: [
      〜省略〜
    ],
  };
}
module.exports = { webpackConfig };

詳細は以下をご参照ください。

https://webpack.js.org/guides/hot-module-replacement/

最後に

今までwebpackは「何だかよく分からないけど複雑そう」という印象を持っていましたが、時間を取って調べたことでかなりイメージを払拭できたように思います。

相変わらず深いところまで理解が及んでいるわけではありませんが、開発環境の納品が必要だったり、何か柔軟な対応が必要な場合には今回構築したwebpackが一役買ってくれそうです。

Viteが使える時は積極的にViteを選択していきたいと思いますが、速度面もwebpack5になってかなり改善しているようですので、第二の選択肢としてこれから使っていきたいと思います!

Discussion

ログインするとコメントできます