Webpack 4 - devServer не перезагружается автоматически при обновлении файлов JSP

Таким образом, моя компания работает над переводом своей кодовой базы внешнего интерфейса на такую ​​платформу, как ReactJS. Мне было поручено разработать процесс сборки внешнего интерфейса с помощью webpack 4. Прямо сейчас мне не нужно поддерживать React, поскольку мы реализуем это позже. Мне просто нужно заменить нашу текущую задачу сборки gulp на webpack 4. Я смог выполнить большую часть этой работы (компиляция HTML, SCSS, CSS, JS). Проблема, с которой я постоянно сталкиваюсь, заключается в том, чтобы заставить webpack знать о содержимом, сгенерированном сервером, в частности о страницах JSP (Java Server Pages). Мне это не нужно, чтобы делать что-то необычное, я просто хочу, чтобы браузер автоматически перезагружался каждый раз, когда страница JSP сохраняется в обновленном состоянии. Я думаю, что это возможно, поскольку наша текущая сборка GULP не может с этим справиться. Я думаю, это может иметь какое-то отношение к Webpack, включая только те файлы, которые, как он знает, вам нужны. Я пробовал много разных конфигураций devServer, и я даже пробовал использовать webpack-browsersync вместе и отдельно от devServer. Файлы включены ниже. Любая помощь по этому вопросу будет принята с благодарностью!

package.json

{
  "scripts": {
    "dev": "node scripts/prepare.js && cross-env NODE_ENV=dev webpack-dev-server --progress --mode development --config webpack.dev.js && node scripts/cleanup.js",
    "build": "node scripts/prepare.js && webpack -p --progress --mode production --config webpack.prod.js && node scripts/cleanup.js",
    "test": "echo \"Error: no test specified\" && exit 1",
    "stats": "webpack --config webpack.prod.js --profile --json > bundle-stats.json && node scripts/cleanup.js"
  },
  "devDependencies": {
    "@babel/core": "^7.2.0",
    "@babel/preset-env": "^7.2.0",
    "@babel/preset-react": "^7.0.0",
    "babel-eslint": "^8.2.6",
    "babel-plugin-syntax-dynamic-import": "^6.18.0",
    "babel-preset-env": "^1.7.0",
    "browser-sync-webpack-plugin": "^2.2.2",
    "concat-with-sourcemaps": "^1.1.0",
    "copy-webpack-plugin": "^4.6.0",
    "cross-env": "^5.2.0",
    "css-loader": "^1.0.0",
    "expose-loader": "^0.7.5",
    "file-loader": "^2.0.0",
    "html-webpack-plugin": "^3.2.0",
    "mini-css-extract-plugin": "^0.4.5",
    "node-sass": "^4.11.0",
    "optimize-css-assets-webpack-plugin": "^5.0.1",
    "raw-loader": "^1.0.0",
    "sass-loader": "^7.1.0",
    "uglify-js": "^3.4.9",
    "uglifyjs-webpack-plugin": "^1.3.0",
    "webpack": "^4.27.1",
    "webpack-cli": "^3.1.0",
    "webpack-dev-server": "^3.1.5",
    "webpack-merge": "^4.1.5",
    "webpack-visualizer-plugin": "^0.1.11",
    "write-file-webpack-plugin": "^4.5.0"
  },
  "dependencies": {
    "babel-loader": "^8.0.0",
    "browser-sync": "^2.26.3",
    "classlist-polyfill": "^1.2.0",
    "element-closest": "^2.0.2",
    "hammerjs": "^2.0.8",
    "jquery": "^1.12.4",
    "jquery-ui": "^1.12.1",
    "js-cookie": "^2.2.0",
    "lodash": "^4.17.10",
    "owl.carousel": "^2.3.4",
    "purecss-sass": "^1.0.0",
    "slick-carousel": "^1.8.1"
  }
}

constants.js

const path = require('path');

module.exports = {
  //use path.resolve for better cross OS compatability
  bases: {
    src: path.resolve(__dirname, '..', 'web/webroot/WEB-INF/_ui-src'),
    dist: path.resolve(__dirname, '..', 'web/webroot/_ui'),
    common: path.resolve(__dirname, '..', 'web/webroot/WEB-INF/_ui-src/responsive/common'),
    storefront: path.resolve(__dirname, '..'),
    webinf: path.resolve(__dirname, '..', 'web/webroot/WEB-INF'),
    views: path.resolve(__dirname, '..', 'web/webroot/WEB-INF/views')
  }
};

webpack.common.js

const webpack = require('webpack');
const path = require('path');
const glob = require('glob');
const constants = require('./scripts/constants');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const WriteFilePlugin = require('write-file-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');

// Is the current build a development build
const isDev = process.env.NODE_ENV === 'dev';
/**
 * This returns an object that has the file path and name
 * as the key and value of the items inside of it
 * i.e. {'./responsive/common/js/file.js' : './responsive/common/js/file.js'}
 * We then use the items in this object to build the path to the
 * destination file so that it matches the directory structure of
 * the source folders to assist with different themes
 */
const getEntry = () => {
  let entry = {};
  let distFilePath = '';
  glob.sync(constants.bases.src + '/**/{bundle.js,pages/*.js,main.scss}').map(element => {
    element = path.resolve(element);
    distFilePath = getDistFilePath(element);
    entry[distFilePath] = `.${element.replace(constants.bases.src, '')}`;
  });
  return entry;
};

/**
 * Because we use a non-standard way of getting our entry files and
 * mapping their output, sometimes we need to transform the output
 * path. This handles the renaming of the output path for special cases.
 * @param {string} filePath
 */
const getDistFilePath = filePath => {
  filePath = `.${filePath.replace(`${constants.bases.src}`, '')}`;

  //remap scss path so output matches path that .tag file expects
  filePath = filePath.replace(
    `${path.sep}scss${path.sep}main.scss`,
    `${path.sep}css${path.sep}main.min`
  );

  return filePath;
};

module.exports = {
  context: constants.bases.src,
  entry: getEntry(),
  output: {
    filename: '[name]',
    path: constants.bases.dist,
    publicPath: '/_ui/'
  },
  resolve: {
    alias: {
      purecss: path.join(__dirname, '/node_modules/purecss-sass/vendor/assets/stylesheets/purecss')
    }
  },
  optimization: {
    minimizer: [
      new UglifyJsPlugin({
        parallel: true,
        sourceMap: true
      }),
      new OptimizeCSSAssetsPlugin({})
    ]
  },
  plugins: [
    new webpack.DefinePlugin({
      isDev: isDev
    }),
    new webpack.ProvidePlugin({
      '_.debounce': 'lodash/debounce',
      '_.throttle': 'lodash/throttle'
    }),
    new MiniCssExtractPlugin({}),
    new CopyWebpackPlugin([
      {
        from: `${constants.bases.common}/images/`,
        to: `${constants.bases.dist}/responsive/common/images/[name].[ext]`,
        toType: 'template',
        debug: 'info'
      },
      {
        from: `${constants.bases.src}/**/fonts/**/*`,
        debug: 'info'
      }
    ]),
    new WriteFilePlugin()
  ],
  module: {
    rules: [
      // Babel
      {
        test: /\.js$/,
        loader: 'babel-loader',
        exclude: /(node_modules|bower_components)/, 
        options: {
          compact: true
        }
      },
      //create a global window object for jQuery
      {
        test: require.resolve('jquery'),
        use: [
          { loader: 'expose-loader', options: '$' },
          { loader: 'expose-loader', options: 'jQuery' }
        ]
      },
      //create a global window object for js-cookie
      {
        test: require.resolve('js-cookie'),
        use: [{ loader: 'expose-loader', options: 'Cookies' }]
      },
      // Styles
      {
        test: /\.(sa|sc|c)ss$/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: {
              url: false,
              sourceMap: isDev
            }
          },
          {
            loader: 'sass-loader',
            options: {
              sourceMap: isDev
            }
          }
        ]
      }
    ]
  }
};

webpack.dev.js

const merge = require('webpack-merge');
const Visualizer = require('webpack-visualizer-plugin');
const BrowserSyncPlugin = require('browser-sync-webpack-plugin');
const common = require('./webpack.common');
const constants = require('./scripts/constants');

module.exports = merge(common, {
  devtool: 'cheap-source-map',
  devServer: {
    contentBase: constants.webinf,
    watchContentBase: true,
    host: '0.0.0.0',
    https: true,
    port: 3000,
    stats: 'errors-only',
    proxy: {
      '/static/content': {
        target: 'https://example.com',
        secure: false
      },
      '/medias': {
        target: 'https://example.com',
        secure: false
      },
      '*': {
        target: 'https://localhost:9002',
        secure: false
      }
    },
    // watchOptions: {
    //   aggregateTimeout: 300,
    //   ignored: /node_modules/,
    //   poll: true
    // }
  },
  plugins: [
    // new BrowserSyncPlugin(
    //   {
    //     host: '0.0.0.0',
    //     port: 3100,
    //     proxy: 'https://localhost:9002/',
    //     open: false,
    //     https: true,
    //     injectChanges: true,
    //     server: {
    //       baseDir: constants.webinf
    //     }
    //   }
    // ),
    new Visualizer({
      filename: `../bundle-stats.html`
    })
  ]
});

File Structure (Simplified)

webpack.common.js
webpack.dev.js
scripts/
 - constants.js
web/
 - webroot/
  - WEB-INF/
   - views/
    - file.JSP << This is not causing an auto-reload even though the content-base on dev server points to all of WEB-INF/ 
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
743
1

Ответы 1

В заключение, я не верю, что есть способ заставить Webpack 4 следить за вашим JSP (или другими страницами, сгенерированными сервером) из коробки, потому что они нигде не требуются / не импортируются, поэтому Webpack не знает о них (поправьте меня если я не прав). В итоге я наткнулся на внешний плагин под названием ExtraWatchWebpackPlugin. Вы можете указать дополнительные каталоги или файлы, которые будут смотреть devServer или BrowserSync. Мой новый файл webpack.dev.js выглядит так:

const merge = require('webpack-merge');
const Visualizer = require('webpack-visualizer-plugin');
const BrowserSyncPlugin = require('browser-sync-webpack-plugin');
const ExtraWatchWebpackPlugin = require('extra-watch-webpack-plugin');
const common = require('./webpack.common');
const constants = require('./scripts/constants');

module.exports = merge(common, {
  devtool: 'cheap-source-map',
  devServer: {
    contentBase: constants.webinf,
    watchContentBase: true,
    host: '0.0.0.0',
    https: true,
    port: 3000,
    stats: 'errors-only',
    proxy: {
      '/static/content': {
        target: 'https://example.com',
        secure: false
      },
      '/medias': {
        target: 'https://example.com',
        secure: false
      },
      '*': {
        target: 'https://localhost:9002',
        secure: false
      }
    },
    watchOptions: {
    //   aggregateTimeout: 300,
    //   poll: true,
    ignored: /node_modules/
    }
  },
  plugins: [
    // new BrowserSyncPlugin(
    //   {
    //     host: '0.0.0.0',
    //     port: 3100,
    //     proxy: 'https://localhost:9002/',
    //     open: false,
    //     https: true,
    //     injectChanges: true,
    //   }
    // ),
    new ExtraWatchWebpackPlugin({
      dirs: [constants.bases.views]
    }),
    new Visualizer({
      filename: `../bundle-stats.html`
    })
  ]
});

Другие вопросы по теме