質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.61%

webpack-dev-serverにてejsのテンプレートファイルのみがwatch対象にならない

受付中

回答 0

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 145

前提

webpack5を使ってjs,scss,ejsファイルをバンドルする環境を構築しようとしております。

概要

開発の際にwebpack-dev-server(以下devserver)を実行しブラウザ上でファイルの変更を確認しているのですが、ejsのテンプレートファイルがwatch対象になっておらずリアルタイムで変更が反映されずに困っています。
原因または解決策のご教授をお願いしたいです。

事象

  • devserverを実行してもtemplateディレクトリ内にあるejsファイルの変更が監視されない
  • 一度devserverを停止し、再度実行すると差分は反映されている(リアルタイムで変更がなされない)
  • templateディレクトリ以外のejsファイル、およびすべてのscss, jsファイルは問題なく監視対象となっている

該当のソースコード

ディレクトリ構成

![ディレクトリ構成

webpack.config.js
const path = require('path');
const globule = require('globule');
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlWebpackHarddiskPlugin = require('html-webpack-harddisk-plugin');
const TerserPlugin = require("terser-webpack-plugin");
const CopyPlugin = require("copy-webpack-plugin");

const assignPlugins = (env_mode) => {
  const srcFiles = globule.find(['**/*.ejs', '!**/_*.ejs'], {cwd: `${__dirname}/src/ejs`});
  const entriesList = {};
  const assignObject = {plugins: [
    new CleanWebpackPlugin({
      cleanOnceBeforeBuildPatterns: [
        'assets/stylesheet',
        'assets/javascript',
      ]
    }),
    new MiniCssExtractPlugin({
      filename: env_mode
        ? 'assets/stylesheet/bundle.css'
        : 'assets/stylesheet/bundle.[contenthash].css',
    }),
    new HtmlWebpackHarddiskPlugin({
      alwaysWriteToDisk: true
    }),
    new CopyPlugin({
      patterns: [
        {from: "src/images/", to: "assets/images/"}
      ]
    })
  ]};

  for(const ejsFileName of srcFiles) {
    const htmlFileName = ejsFileName.replace(new RegExp(`.ejs`, 'i'), `.html`);
    entriesList[htmlFileName] = `${__dirname}/src/ejs/${ejsFileName}`;
  }

  for(const [htmlFileName, ejsFileName] of Object.entries(entriesList)) {
    assignObject.plugins.push(new HtmlWebpackPlugin({
      filename : htmlFileName,
      template : ejsFileName,
      inject: 'body',
      minify: env_mode ?
        false :
        {
          collapseWhitespace: false,
          removeComments: true,
        },
    }));
  }

  return assignObject;
};

module.exports = (env, argv) => {
  const is_DEVELOP = argv.mode === "development";

  return [
    Object.assign({
      entry: './src/js/main',
      output: {
        path: path.join(__dirname, 'public'),
        filename: is_DEVELOP
          ? 'assets/javascript/bundle.js'
          : 'assets/javascript/bundle.[contenthash].js',
      },
      devtool: is_DEVELOP ? 'source-map' : 'eval',
      watchOptions: {
        ignored: /node_modules/
      },
      resolve: {
        extensions: ['.js', '.ts'],
      },

      optimization: {
        minimize: is_DEVELOP ? false : true,
        minimizer: [
          new TerserPlugin({
            terserOptions: {
              ecma: 2020,
            }
          })
        ]
      },

      module: {
        rules: [
          {
            test: /\.ejs$/,
            use: 'ejs-compiled-loader',
          },
          {
            test: /\.scss$/,
            use: [
              MiniCssExtractPlugin.loader,
              {
                loader: 'css-loader',
                options: {
                  url: false,
                  sourceMap: true,
                },
              },
              {
                loader: 'postcss-loader',
                options: {
                  postcssOptions: {
                    plugins: [
                      [
                        require('autoprefixer')({grid: true}),
                      ],
                    ],
                  }
                }
              },
              {
                loader: 'sass-loader',
                options: {
                  implementation: require('sass'),
                },
              },
            ]
          },
          {
            test: /\.js$/,
            exclude: /node_modules/,
            use: [
              {
                loader: 'babel-loader',
                options: {
                  presets: ['@babel/preset-env', '@babel/preset-react'],
                  plugins: ['@babel/plugin-transform-runtime'],
                },
              },
            ],
          },
          {
            enforce: 'pre',
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'eslint-loader',
          },
        ],
      },
      devServer: {
        contentBase: path.resolve(__dirname, 'public'),
        port: 8080,
      },
      stats: {
        children: true
      },
      target: is_DEVELOP ?
        "web" :
        ["web", "es5"]
      }, assignPlugins(is_DEVELOP))
  ]
}
index.ejs

index.ejsでは以下のようにテンプレートファイルをincludeしています。

<% var title = "TOP"; var description = "description"; %>
<% var path = '/assets/images/'; %>

<% include ./template/_head %>

<% include ./template/_header %>

<main  class="l-main">
 ...
</main>
<!-- l-footer -->
<% include ./template/_footer %>
package.json
{
   ...
  "scripts": {
    "start": "webpack serve --mode=development",
    "dev": "webpack --mode=development",
    "prod": "webpack --mode=production",
    "watch": "webpack -w --mode=development"
  },
  "devDependencies": {
       ...
  }
}
devserver起動時のログ
$ yarn start
yarn run v1.22.10
$ webpack serve --mode=development
ℹ 「wds」: Project is running at http://localhost:8080/
ℹ 「wds」: webpack output is served from /
ℹ 「wds」: Content not from webpack is served from /path/to/dir/public
(node:44401) [DEP0148] DeprecationWarning: Use of deprecated folder mapping "./" in the "exports" field module resolution of the package at /path/to/dir/node_modules/css-loader/node_modules/postcss/package.json.
Update this package.json to use a subpath pattern like "./*".
(Use `node --trace-deprecation ...` to show where the warning was created)
ℹ 「wdm」: assets by path assets/ 392 KiB
  asset assets/javascript/bundle.js 387 KiB [emitted] (name: main) 1 related asset
  asset assets/stylesheet/bundle.css 5.45 KiB [emitted] (name: main) 1 related asset
asset index.html 4.98 KiB [emitted]
asset about/index.html 1.75 KiB [emitted]
Entrypoint main 392 KiB (449 KiB) = assets/stylesheet/bundle.css 5.45 KiB assets/javascript/bundle.js 387 KiB 2 auxiliary assets
runtime modules 1.25 KiB 6 modules
modules by path ./node_modules/ 361 KiB
  modules by path ./node_modules/webpack-dev-server/ 21.2 KiB 12 modules
  modules by path ./node_modules/html-entities/lib/.js 61 KiB 5 modules
  modules by path ./node_modules/@babel/runtime/ 1.55 KiB 4 modules
  modules by path ./node_modules/webpack/hot/ 1.58 KiB 3 modules
  modules by path ./node_modules/querystring/.js 4.51 KiB 3 modules
  modules by path ./node_modules/url/.js 23.1 KiB 2 modules
modules by path ./src/ 4.31 KiB (javascript) 5.42 KiB (css/mini-extract)
  modules by path ./src/js/ 4.27 KiB 3 modules
  modules by path ./src/scss/ *.scss 50 bytes (javascript) 5.42 KiB (css/mini-extract)
    ./src/scss/app.scss 50 bytes [built] [code generated]
    css ./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[1].use[1]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[1].use[2]!./node_modules/sass-loader/dist/cjs.js??ruleSet[1].rules[1].use[3]!./src/scss/app.scss 5.42 KiB [code generated]
  Entrypoint HtmlWebpackPlugin_0-0 =
  Entrypoint HtmlWebpackPlugin_1-0 =
  runtime modules 1.43 KiB 8 modules
  cacheable modules 9.14 KiB
    data:text/javascript,__webpack_public_path__ = __webpack_base_uri__ = htmlWebpackPluginPublicPath; 77 bytes [built] [code generated]
    ./node_modules/html-webpack-plugin/lib/loader.js!./src/ejs/index.ejs 6.22 KiB [built] [code generated]
    ./node_modules/html-webpack-plugin/lib/loader.js!./src/ejs/about/index.ejs 2.85 KiB [built] [code generated]

  Child HtmlWebpackCompiler compiled successfully

  Entrypoint child =
  runtime modules 937 bytes 4 modules
  cacheable modules 21 KiB
    ./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[1].use[1]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[1].use[2]!./node_modules/sass-loader/dist/cjs.js??ruleSet[1].rules[1].use[3]!./src/scss/app.scss 17.3 KiB [built] [code generated]
    ./node_modules/css-loader/dist/runtime/cssWithMappingToString.js 2.21 KiB [built] [code generated]
    ./node_modules/css-loader/dist/runtime/api.js 1.57 KiB [built] [code generated]

  Child mini-css-extract-plugin /path/to/dir/node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[1].use[1]!/path/to/dir/node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[1].use[2]!/path/to/dir/node_modules/sass-loader/dist/cjs.js??ruleSet[1].rules[1].use[3]!/path/to/dir/src/scss/app.scss compiled successfully
webpack 5.28.0 compiled successfully in 1357 ms
ℹ 「wdm」: Compiled successfully.
  • npm startによってdevserverが実行されます
  • ejsファイルはejs-compiled-loaderを通りhtml-webpack-pluginによって自動生成されます。
  • modeによってjs,scssファイルのソースマップやminifyの切り替えをしています。htmlファイルはいずれのmodeでも非圧縮で出力します。

試したこと

  • devserverの問題かと思いwebpackのwatchモードを実行してみましたが、同様にtamplateディレクトリ内のejsファイルのみ監視対象となりませんでした
  • ejs-html-loaderejs-plain-loaderなどのその他のloaderも試してみましたが、同様の結果でした

マシン環境

  • MacBook Air (M1, 2020) Big Sur v11.3.1
  • node: v16.2.0
  • npm: v7.13.0
  • yarn: v1.22.10

よろしくお願いいたします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

まだ回答がついていません

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.61%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る