webpack configuration for development and production in a single file

Managing webpack's configuration for development and production environments usually involves creating three files (one for common settings, one for development, and one for production), and then merging them requiring a package.

When it's possible, it makes more sense to me to have all the configuration in one single file, because much of the code is shared between development and production anyway, and the specific can be handled easily with conditional statements. Furthermore, we don't have to keep track of files, making sure they work correctly together, and also save the need for an extra dependency.

We can change the environment depending on the mode variable of the configuration, by exporting a function instead of an object, creating a condition (additionally to the development and production modes there is the 'none' mode which opts out of any default optimization, so we define the condition as anything that is not 'production'), and adding the condition to the settings that are specific to each mode:

const path = require("path")
const HtmlWebpackPlugin = require("html-webpack-plugin")
const CompressionPlugin = require("compression-webpack-plugin")

module.exports = (env, options) => {
  const isDevelopment = options.mode !== "production"

  return {
    mode: isDevelopment ? "development" : "production",
    output: {
      filename: isDevelopment ? "[name].js" : "[name].[contenthash:8].js",
    devtool: isDevelopment ? "eval-cheap-module-source-map" : "nosources-source-map",
    plugins: [
      new HtmlWebpackPlugin({
        minify: isDevelopment
          ? false
          : {
              collapseWhitespace: true,
              keepClosingSlash: true,
              minifyCSS: true,
              minifyJS: true,
              minifyURLs: true,
              removeComments: true,
              removeEmptyAttributes: true,
              removeRedundantAttributes: true,
              removeScriptTypeAttributes: true,
              removeStyleLinkTypeAttributes: true,
              useShortDoctype: true,
        ? []
        : [
            new CompressionPlugin({
              algorithm: "brotliCompress",
              compressionOptions: {level: 11},
              filename: "[name][ext].br",
              test: /\.(js|css|html|svg)$/,

In this simplified example with some common options that can benefit from having a dual configuration, for each mode we have a different output filename, devtool, and performance hint behavior, and we disable HTML minification and files compression for development.

Obviously every project has its needs and there may be cases where it makes more sense to split up the configuration, but for small or medium projects this can help to simplify the process a bit. You can see an example file here.

If you're using dark mode, do you like the code blocks's theme? I have it available for VS Code, feel free to check it.