about summary refs log tree commit diff
path: root/config/webpack
diff options
context:
space:
mode:
Diffstat (limited to 'config/webpack')
-rw-r--r--config/webpack/configuration.js4
-rw-r--r--config/webpack/development.js40
-rw-r--r--config/webpack/loaders/assets.js12
-rw-r--r--config/webpack/loaders/babel.js12
-rw-r--r--config/webpack/loaders/babel_external.js21
-rw-r--r--config/webpack/production.js28
-rw-r--r--config/webpack/rules/babel.js21
-rw-r--r--config/webpack/rules/css.js (renamed from config/webpack/loaders/sass.js)9
-rw-r--r--config/webpack/rules/file.js20
-rw-r--r--config/webpack/rules/index.js14
-rw-r--r--config/webpack/rules/mark.js (renamed from config/webpack/loaders/mark.js)0
-rw-r--r--config/webpack/rules/node_modules.js26
-rw-r--r--config/webpack/shared.js17
13 files changed, 141 insertions, 83 deletions
diff --git a/config/webpack/configuration.js b/config/webpack/configuration.js
index 4d325a828..80a094c72 100644
--- a/config/webpack/configuration.js
+++ b/config/webpack/configuration.js
@@ -1,12 +1,11 @@
 // Common configuration for webpacker loaded from config/webpacker.yml
 
-const { join, resolve } = require('path');
+const { resolve } = require('path');
 const { env } = require('process');
 const { safeLoad } = require('js-yaml');
 const { readFileSync } = require('fs');
 
 const configPath = resolve('config', 'webpacker.yml');
-const loadersDir = join(__dirname, 'loaders');
 const settings = safeLoad(readFileSync(configPath), 'utf8')[env.RAILS_ENV || env.NODE_ENV];
 
 const themePath = resolve('config', 'themes.yml');
@@ -37,6 +36,5 @@ module.exports = {
     CDN_HOST: env.CDN_HOST,
     NODE_ENV: env.NODE_ENV,
   },
-  loadersDir,
   output,
 };
diff --git a/config/webpack/development.js b/config/webpack/development.js
index d54d919ec..1e50a4f46 100644
--- a/config/webpack/development.js
+++ b/config/webpack/development.js
@@ -1,12 +1,10 @@
 // Note: You must restart bin/webpack-dev-server for changes to take effect
 
 const merge = require('webpack-merge');
-const sharedConfig = require('./shared.js');
-const { settings, output } = require('./configuration.js');
+const sharedConfig = require('./shared');
+const { settings, output } = require('./configuration');
 
-const watchOptions = {
-  ignored: /node_modules/,
-};
+const watchOptions = {};
 
 if (process.env.VAGRANT) {
   // If we are in Vagrant, we can't rely on inotify to update us with changed
@@ -17,7 +15,7 @@ if (process.env.VAGRANT) {
 
 module.exports = merge(sharedConfig, {
   mode: 'development',
-
+  cache: true,
   devtool: 'cheap-module-eval-source-map',
 
   stats: {
@@ -30,15 +28,33 @@ module.exports = merge(sharedConfig, {
 
   devServer: {
     clientLogLevel: 'none',
-    https: settings.dev_server.https,
+    compress: settings.dev_server.compress,
+    quiet: settings.dev_server.quiet,
+    disableHostCheck: settings.dev_server.disable_host_check,
     host: settings.dev_server.host,
     port: settings.dev_server.port,
+    https: settings.dev_server.https,
+    hot: settings.dev_server.hmr,
     contentBase: output.path,
+    inline: settings.dev_server.inline,
+    useLocalIp: settings.dev_server.use_local_ip,
+    public: settings.dev_server.public,
     publicPath: output.publicPath,
-    compress: true,
-    headers: { 'Access-Control-Allow-Origin': '*' },
-    historyApiFallback: true,
-    disableHostCheck: true,
-    watchOptions: watchOptions,
+    historyApiFallback: {
+      disableDotRule: true,
+    },
+    headers: settings.dev_server.headers,
+    overlay: settings.dev_server.overlay,
+    stats: {
+      entrypoints: false,
+      errorDetails: false,
+      modules: false,
+      moduleTrace: false,
+    },
+    watchOptions: Object.assign(
+      {},
+      settings.dev_server.watch_options,
+      watchOptions
+    ),
   },
 });
diff --git a/config/webpack/loaders/assets.js b/config/webpack/loaders/assets.js
deleted file mode 100644
index 643b3eeb0..000000000
--- a/config/webpack/loaders/assets.js
+++ /dev/null
@@ -1,12 +0,0 @@
-const { env, publicPath } = require('../configuration.js');
-
-module.exports = {
-  test: /\.(jpg|jpeg|png|gif|svg|eot|ttf|woff|woff2)$/i,
-  use: [{
-    loader: 'file-loader',
-    options: {
-      publicPath,
-      name: env.NODE_ENV === 'production' ? '[name]-[hash].[ext]' : '[name].[ext]',
-    },
-  }],
-};
diff --git a/config/webpack/loaders/babel.js b/config/webpack/loaders/babel.js
deleted file mode 100644
index 7509617fd..000000000
--- a/config/webpack/loaders/babel.js
+++ /dev/null
@@ -1,12 +0,0 @@
-const { resolve } = require('path');
-
-const env = process.env.NODE_ENV || 'development';
-
-module.exports = {
-  test: /\.js$/,
-  exclude: /node_modules/,
-  loader: 'babel-loader',
-  options: {
-    cacheDirectory: env === 'development' ? false : resolve(__dirname, '..', '..', '..', 'tmp', 'cache', 'babel-loader'),
-  },
-};
diff --git a/config/webpack/loaders/babel_external.js b/config/webpack/loaders/babel_external.js
deleted file mode 100644
index 39e74ed90..000000000
--- a/config/webpack/loaders/babel_external.js
+++ /dev/null
@@ -1,21 +0,0 @@
-const { resolve } = require('path');
-
-const env = process.env.NODE_ENV || 'development';
-
-if (env === 'development') {
-  module.exports = {};
-} else {
-  // babel options to apply only to external libraries, e.g. remove-prop-types
-  module.exports = {
-    test: /\.js$/,
-    include: /node_modules/,
-    loader: 'babel-loader',
-    options: {
-      babelrc: false,
-      plugins: [
-        'transform-react-remove-prop-types',
-      ],
-      cacheDirectory: env === 'development' ? false : resolve(__dirname, '..', '..', '..', 'tmp', 'cache', 'babel-loader-external'),
-    },
-  };
-}
diff --git a/config/webpack/production.js b/config/webpack/production.js
index d37e11792..cae978fcb 100644
--- a/config/webpack/production.js
+++ b/config/webpack/production.js
@@ -1,15 +1,15 @@
 // Note: You must restart bin/webpack-dev-server for changes to take effect
 
+const path = require('path');
+const { URL } = require('url');
 const merge = require('webpack-merge');
+const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
+const OfflinePlugin = require('offline-plugin');
 const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
 const CompressionPlugin = require('compression-webpack-plugin');
 const zopfli = require('@gfx/zopfli');
-const sharedConfig = require('./shared.js');
-const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
-const OfflinePlugin = require('offline-plugin');
-const { publicPath } = require('./configuration.js');
-const path = require('path');
-const { URL } = require('url');
+const { output } = require('./configuration');
+const sharedConfig = require('./shared');
 
 let attachmentHost;
 
@@ -28,15 +28,9 @@ if (process.env.S3_ENABLED === 'true') {
 
 module.exports = merge(sharedConfig, {
   mode: 'production',
-
-  output: {
-    filename: '[name]-[chunkhash].js',
-    chunkFilename: '[name]-[chunkhash].js',
-  },
-
-  devtool: 'source-map', // separate sourcemap file, suitable for production
+  devtool: 'source-map',
   stats: 'normal',
-
+  bail: true,
   optimization: {
     minimize: true,
     minimizer: [
@@ -60,10 +54,12 @@ module.exports = merge(sharedConfig, {
 
   plugins: [
     new CompressionPlugin({
+      filename: '[path].gz[query]',
       algorithm(input, compressionOptions, callback) {
         return zopfli.gzip(input, compressionOptions, callback);
       },
-      test: /\.(js|css|html|json|ico|svg|eot|otf|ttf)$/,
+      cache: true,
+      test: /\.(js|css|html|json|ico|svg|eot|otf|ttf|map)$/,
     }),
     new BundleAnalyzerPlugin({ // generates report.html and stats.json
       analyzerMode: 'static',
@@ -76,7 +72,7 @@ module.exports = merge(sharedConfig, {
       logLevel: 'silent', // do not bother Webpacker, who runs with --json and parses stdout
     }),
     new OfflinePlugin({
-      publicPath: publicPath, // sw.js must be served from the root to avoid scope issues
+      publicPath: output.publicPath, // sw.js must be served from the root to avoid scope issues
       caches: {
         main: [':rest:'],
         additional: [':externals:'],
diff --git a/config/webpack/rules/babel.js b/config/webpack/rules/babel.js
new file mode 100644
index 000000000..2fc245c43
--- /dev/null
+++ b/config/webpack/rules/babel.js
@@ -0,0 +1,21 @@
+const { join, resolve } = require('path');
+const { env, settings } = require('../configuration');
+
+module.exports = {
+  test: /\.(js|jsx|mjs)$/,
+  include: [
+    settings.source_path,
+    ...settings.resolved_paths,
+  ].map(p => resolve(p)),
+  exclude: /node_modules/,
+  use: [
+    {
+      loader: 'babel-loader',
+      options: {
+        cacheDirectory: join(settings.cache_path, 'babel-loader'),
+        cacheCompression: env.NODE_ENV === 'production',
+        compact: env.NODE_ENV === 'production',
+      },
+    },
+  ],
+};
diff --git a/config/webpack/loaders/sass.js b/config/webpack/rules/css.js
index 67a1890b8..27905a617 100644
--- a/config/webpack/loaders/sass.js
+++ b/config/webpack/rules/css.js
@@ -4,7 +4,14 @@ module.exports = {
   test: /\.s?css$/i,
   use: [
     MiniCssExtractPlugin.loader,
-    'css-loader',
+    {
+      loader: 'css-loader',
+      options: {
+        sourceMap: true,
+        importLoaders: 2,
+        localIdentName: '[name]__[local]___[hash:base64:5]',
+      },
+    },
     {
       loader: 'postcss-loader',
       options: {
diff --git a/config/webpack/rules/file.js b/config/webpack/rules/file.js
new file mode 100644
index 000000000..f2fb58780
--- /dev/null
+++ b/config/webpack/rules/file.js
@@ -0,0 +1,20 @@
+const { join } = require('path');
+const { settings } = require('../configuration');
+
+module.exports = {
+  test: new RegExp(`(${settings.static_assets_extensions.join('|')})$`, 'i'),
+  use: [
+    {
+      loader: 'file-loader',
+      options: {
+        name(file) {
+          if (file.includes(settings.source_path)) {
+            return 'media/[path][name]-[hash].[ext]';
+          }
+          return 'media/[folder]/[name]-[hash:8].[ext]';
+        },
+        context: join(settings.source_path),
+      },
+    },
+  ],
+};
diff --git a/config/webpack/rules/index.js b/config/webpack/rules/index.js
new file mode 100644
index 000000000..bbf6b0187
--- /dev/null
+++ b/config/webpack/rules/index.js
@@ -0,0 +1,14 @@
+const babel = require('./babel');
+const css = require('./css');
+const file = require('./file');
+const nodeModules = require('./node_modules');
+
+// Webpack loaders are processed in reverse order
+// https://webpack.js.org/concepts/loaders/#loader-features
+// Lastly, process static files using file loader
+module.exports = {
+  file,
+  css,
+  nodeModules,
+  babel,
+};
diff --git a/config/webpack/loaders/mark.js b/config/webpack/rules/mark.js
index e62a526b0..e62a526b0 100644
--- a/config/webpack/loaders/mark.js
+++ b/config/webpack/rules/mark.js
diff --git a/config/webpack/rules/node_modules.js b/config/webpack/rules/node_modules.js
new file mode 100644
index 000000000..422554a76
--- /dev/null
+++ b/config/webpack/rules/node_modules.js
@@ -0,0 +1,26 @@
+const { join } = require('path');
+const { settings, env } = require('../configuration');
+
+module.exports = {
+  test: /\.(js|mjs)$/,
+  include: /node_modules/,
+  exclude: /@babel(?:\/|\\{1,2})runtime/,
+  use: [
+    {
+      loader: 'babel-loader',
+      options: {
+        babelrc: false,
+        presets: [
+          ['@babel/env', { modules: false }],
+        ],
+        plugins: [
+          'transform-react-remove-prop-types',
+        ],
+        cacheDirectory: join(settings.cache_path, 'babel-loader-node-modules'),
+        cacheCompression: env.NODE_ENV === 'production',
+        compact: false,
+        sourceMaps: false,
+      },
+    },
+  ],
+};
diff --git a/config/webpack/shared.js b/config/webpack/shared.js
index d6199373b..cb4e5a85f 100644
--- a/config/webpack/shared.js
+++ b/config/webpack/shared.js
@@ -6,7 +6,8 @@ const { sync } = require('glob');
 const MiniCssExtractPlugin = require('mini-css-extract-plugin');
 const AssetsManifestPlugin = require('webpack-assets-manifest');
 const extname = require('path-complete-extname');
-const { env, settings, themes, output, loadersDir } = require('./configuration.js');
+const { env, settings, themes, output } = require('./configuration');
+const rules = require('./rules');
 const localePackPaths = require('./generateLocalePacks');
 
 const extensionGlob = `**/*{${settings.extensions.join(',')}}*`;
@@ -33,8 +34,9 @@ module.exports = {
   ),
 
   output: {
-    filename: '[name].js',
-    chunkFilename: '[name].js',
+    filename: 'js/[name]-[chunkhash].js',
+    chunkFilename: 'js/[name]-[chunkhash].chunk.js',
+    hotUpdateChunkFilename: 'js/[id]-[hash].hot-update.js',
     path: output.path,
     publicPath: output.publicPath,
   },
@@ -60,7 +62,7 @@ module.exports = {
   },
 
   module: {
-    rules: sync(join(loadersDir, '*.js')).map(loader => require(loader)),
+    rules: Object.keys(rules).map(key => rules[key]),
   },
 
   plugins: [
@@ -73,11 +75,14 @@ module.exports = {
       }
     ),
     new MiniCssExtractPlugin({
-      filename: env.NODE_ENV === 'production' ? '[name]-[contenthash].css' : '[name].css',
+      filename: 'css/[name]-[contenthash:8].css',
+      chunkFilename: 'css/[name]-[contenthash:8].chunk.css',
     }),
     new AssetsManifestPlugin({
-      publicPath: true,
+      integrity: false,
+      entrypoints: true,
       writeToDisk: true,
+      publicPath: true,
     }),
   ],