Webpack Optimization Techniques and Configuration Splitting

Performance Optimization Strategies

Skip Parsing with noParse

When third-party libraries like jQuery or Lodash—known to have no internal dependencies—are included in a project, parsing them during bundling is unnecessary. The noParse option instructs Webpack to skip parsing these files, improving build speed.

module: {
  noParse: /jquery|lodash/
}

Exclude Unneeded Modules via IgnorePlugin

The built-in IgnorePlugin prevents specific modules from being bundled. For instance, moment.js includes numerous locale files by default, which may bloat the bundle. Using this plugin, unwanted locales can be excluded, and only required ones imported manually.

// webpack.config.js
plugins: [
  new webpack.IgnorePlugin({
    resourceRegExp: /^\.\/locale$/,
    contextRegExp: /moment$/
  })
]

// index.js
import moment from 'moment';
import 'moment/locale/zh-cn';
moment.locale('zh-cn');

Pre-bundle Dependencies with DllPlugin

Third-party dependencies rarely change between builds. DllPlugin allows these to be pre-bundled into a dynamic link library (DLL), significantly speeding up subsequent builds. This requires two configuration files: one for the DLL and another for the main application.

The plugin generates a manifest.json file, which DllReferencePlugin uses to reference the pre-built dependencies at runtime.

Parallelize Loaders with thread-loader

For CPU-intensive tasks like Babel or CSS processing, thread-loader enables parallel execution across worker threads. It should be placed before other loaders in the chain.

{
  test: /\.m?js$/,
  include: path.resolve(__dirname, 'src'),
  exclude: /node_modules/,
  use: [
    'thread-loader',
    {
      loader: 'babel-loader',
      options: {
        presets: [['@babel/preset-env', {
          useBuiltIns: 'entry',
          corejs: 3,
          targets: { chrome: '58', ie: '11' }
        }]],
        plugins: ['@babel/plugin-transform-runtime']
      }
    }
  ]
}

Note: Webpack 4+ already uses multi-threading for minification via TerserWebpackPlugin, so thread-loader offers diminishing returns on small projects.

Enable Hot Module Replacement (HMR)

HMR allows updating modules in a running application without full page reloads. While webpack-dev-server supports HMR, explicit configuration is needed.

// webpack.config.js
const webpack = require('webpack');

module.exports = {
  devServer: { hot: true },
  plugins: [new webpack.HotModuleReplacementPlugin()]
};

// index.js
if (module.hot) {
  module.hot.accept();
}

HMR is development-only and incompatible with MiniCssExtractPlugin; use style-loader during development for CSS HMR support.

Environment-Specific Configuration Splitting

To manage different build requirements across environments, split the configuration into:

  • webpack.base.js – shared settings
  • webpack.dev.js – development-specific
  • webpack.prod.js – production optimizations
  • webpack.dll.js – DLL bundling

Use webpack-merge to combine them:

npm install --save-dev webpack-merge

Directory Structure

build/
├── webpack.base.js
├── webpack.dev.js
├── webpack.prod.js
└── webpack.dll.js
config/
├── dev.env.js
└── prod.env.js
public/lib/
├── vendor.dll.dev.js
├── vendor.dll.prod.js
├── vendor.manifest.dev.json
└── vendor.manifest.prod.json
src/
└── ...

DLL Configuration (webpack.dll.js)

const path = require('path');
const webpack = require('webpack');
const TerserPlugin = require('terser-webpack-plugin');

const isDev = process.env.ENV_CONFIG === 'dev';
const mode = isDev ? 'development' : 'production';
const suffix = isDev ? 'dev' : 'prod';

module.exports = {
  mode,
  entry: {
    vendor: ['vue', 'vue-router', 'vuex', 'element-plus', 'core-js']
  },
  output: {
    path: path.resolve(__dirname, '../public/lib'),
    filename: `[name].dll.${suffix}.js`,
    library: '[name]_lib'
  },
  plugins: [
    new webpack.DllPlugin({
      name: '[name]_lib',
      path: path.resolve(__dirname, `../public/lib/[name].manifest.${suffix}.json`)
    })
  ],
  optimization: {
    minimizer: [
      new TerserPlugin({
        parallel: true,
        extractComments: false,
        terserOptions: {
          compress: {
            drop_debugger: true
          }
        }
      })
    ]
  }
};

Base Configuration (webpack.base.js)

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { VueLoaderPlugin } = require('vue-loader');
const webpack = require('webpack');

const envVars = require(`../config/${process.env.ENV_CONFIG}.env.js`);

module.exports = {
  context: path.resolve(__dirname, '..'),
  entry: {
    home: './src/index.js',
    other: './src/other.js'
  },
  output: {
    filename: 'js/[name].[contenthash].js',
    path: path.resolve(__dirname, '../dist'),
    clean: true
  },
  plugins: [
    new webpack.DefinePlugin({
      _WBPACK_ENV_VARIABLE: JSON.stringify(envVars)
    }),
    new VueLoaderPlugin()
  ],
  module: {
    rules: [
      {
        test: /\.vue$/,
        use: ['thread-loader', 'vue-loader']
      },
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'postcss-loader',
          'thread-loader'
        ]
      },
      // ... asset loaders for images, fonts, media
    ]
  },
  resolve: {
    extensions: ['.js', '.vue', '.css', '.json'],
    alias: {
      '@': path.resolve(__dirname, '../src'),
      '@assets': path.resolve(__dirname, '../src/assets')
    }
  }
};

Development Config (webpack.dev.js)

const { merge } = require('webpack-merge');
const base = require('./webpack.base');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const webpack = require('webpack');
const path = require('path');

module.exports = merge(base, {
  mode: 'development',
  devtool: 'source-map',
  output: { publicPath: '/' },
  devServer: {
    port: 3001,
    host: '0.0.0.0',
    hot: true,
    proxy: [{ context: ['/api'], target: 'http://localhost:3000' }]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      filename: 'index.html',
      chunks: ['home'],
      title: 'Webpack Dev Setup',
      path: '/lib/vendor.dll.dev.js'
    }),
    new MiniCssExtractPlugin({ filename: 'css/[name].css' }),
    new CopyPlugin({
      patterns: [{
        from: 'public',
        to: '.',
        globOptions: { ignore: ['**/*.prod.*'] }
      }]
    }),
    new webpack.DllReferencePlugin({
      manifest: path.resolve(__dirname, '../public/lib/vendor.manifest.dev.json')
    }),
    new webpack.HotModuleReplacementPlugin()
  ]
});

Production Config (webpack.prod.js)

const { merge } = require('webpack-merge');
const base = require('./webpack.base');
const TerserPlugin = require('terser-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const webpack = require('webpack');
const path = require('path');

module.exports = merge(base, {
  mode: 'production',
  devtool: 'source-map',
  output: { publicPath: '/dist/' },
  optimization: {
    minimizer: [
      new CssMinimizerPlugin({ parallel: true }),
      new TerserPlugin({
        parallel: true,
        extractComments: false,
        terserOptions: { compress: { drop_debugger: true } }
      })
    ]
  },
  module: {
    rules: [
      {
        test: /\.m?js$/,
        include: path.resolve(__dirname, '../src'),
        exclude: /node_modules/,
        use: ['thread-loader', 'babel-loader']
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      filename: 'index.html',
      chunks: ['home'],
      minify: { collapseWhitespace: true, removeAttributeQuotes: true },
      title: 'Webpack Prod Build',
      path: '/dist/lib/vendor.dll.prod.js'
    }),
    new MiniCssExtractPlugin({ filename: 'css/[name].[fullhash].css' }),
    new CopyPlugin({
      patterns: [{
        from: 'public',
        to: '.',
        globOptions: { ignore: ['**/*.dev.*'] }
      }]
    }),
    new webpack.DllReferencePlugin({
      manifest: path.resolve(__dirname, '../public/lib/vendor.manifest.prod.json')
    })
  ]
});

Build scripts in package.json:

"scripts": {
  "dev": "cross-env ENV_CONFIG=dev webpack serve --config build/webpack.dev.js",
  "build": "cross-env ENV_CONFIG=prod webpack --config build/webpack.prod.js",
  "dll:dev": "cross-env ENV_CONFIG=dev webpack --config build/webpack.dll.js",
  "dll:prod": "cross-env ENV_CONFIG=prod webpack --config build/webpack.dll.js"
}

Tags: webpack Optimization build-tools frontend javascript

Posted on Wed, 13 May 2026 17:01:02 +0000 by no_one