【问题标题】:Webpack 4 - devServer not auto-reloading when JSP files are updatedWebpack 4 - 更新 JSP 文件时 devServer 不会自动重新加载
【发布时间】:2019-05-14 18:05:00
【问题描述】:

总之,我的公司正在努力将他们的前端代码库转换为像 ReactJS 这样的框架。我的任务是使用 webpack 4 开发前端构建过程。现在我不需要支持 React,因为我们稍后会实现它。我只需要用 webpack 4 替换我们当前的 gulp 构建任务。我已经能够完成大部分工作(HTML、SCSS、CSS、JS 编译)。我一直遇到的问题是让 webpack 了解服务器生成的内容,特别是 JSP(Java 服务器页面)页面。我不需要它做任何花哨的事情,我只希望浏览器在 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`
    })
  ]
});

文件结构(简体)

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/ 

【问题讨论】:

    标签: jsp webpack webpack-dev-server browser-sync webpack-4


    【解决方案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`
        })
      ]
    });
    

    【讨论】:

      猜你喜欢
      • 2021-12-01
      • 2019-02-18
      • 2016-05-23
      • 1970-01-01
      • 2017-08-01
      • 1970-01-01
      • 2017-05-03
      • 1970-01-01
      • 2020-08-08
      相关资源
      最近更新 更多