Printable

Configuration

Out of the box, webpack won't require you to use a configuration file. However, it will assume the entry point of your project is src/index.js and will output the result in dist/main.js minified and optimized for production.

Usually, your projects will need to extend this functionality, for this you can create a webpack.config.js file in the root folder and webpack will automatically use it.

All the available configuration options are specified below.

Use a different configuration file

If for some reason you want to use a different configuration file depending on certain situations, you can change this via command line by using the --config flag.

package.json

"scripts": {
  "build": "webpack --config prod.config.js"
}

Set up a new webpack project

Webpack has a huge set of options which might be overwhelming to you, please take advantage of webpack-cli starting from version v6.0.0 new tool create-new-webpack-app which could rapidly generate webpack application with specific configuration files for your project requirements, it will ask you a couple of questions before creating a configuration file.

npx create-new-webpack-app [command] [options]

npx might prompt you to install create-new-webpack-app if it is not yet installed in the project or globally. You might also get additional packages installed to your project depending on the choices you've made during the new webpack application generation.

$ npx create-new-webpack-app init

Need to install the following packages:
[email protected]
Ok to proceed? (y)

? Which of the following JS solutions do you want to use? Typescript
? Do you want to use webpack-dev-server? Yes
? Do you want to simplify the creation of HTML files for your bundle? Yes
? Do you want to add PWA support? No
? Which of the following CSS solutions do you want to use? CSS only
? Will you be using PostCSS in your project? Yes
? Do you want to extract CSS for every file? Only for Production
? Which package manager do you want to use? npm
[create-webpack] ℹ️ Initializing a new Webpack project
...
...
...
[create-webpack] ✅ Project dependencies installed successfully!
[create-webpack] ✅ Project has been initialised with webpack!

Configuration Languages

Webpack accepts configuration files written in multiple programming and data languages. The list of supported file extensions can be found in the node-interpret package. Using node-interpret, webpack can handle many different types of configuration files.

TypeScript

To write the webpack configuration in TypeScript, you would first install the necessary dependencies, i.e., TypeScript and the relevant type definitions from the DefinitelyTyped project:

npm install --save-dev typescript ts-node @types/node @types/webpack
# and, if using webpack-dev-server < v4.7.0
npm install --save-dev @types/webpack-dev-server

and then proceed to write your configuration:

webpack.config.ts

import path from 'path';
import webpack from 'webpack';
// in case you run into any typescript error when configuring `devServer`
import 'webpack-dev-server';

const config: webpack.Configuration = {
  mode: 'production',
  entry: './foo.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'foo.bundle.js',
  },
};

export default config;

tsconfig.json

{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true
  }
}

The above sample assumes version >= 2.7 or newer of TypeScript is used with the new esModuleInterop and allowSyntheticDefaultImports compiler options in your tsconfig.json file.

Note that you'll also need to check your tsconfig.json file. If the module in compilerOptions in tsconfig.json is commonjs, the setting is complete, else webpack will fail with an error. This occurs because ts-node does not support any module syntax other than commonjs.

There are three solutions to this issue:

  • Modify tsconfig.json.
  • Modify tsconfig.json and add settings for ts-node.
  • Install tsconfig-paths.

The first option is to open your tsconfig.json file and look for compilerOptions. Set target to "ES5" and module to "CommonJS" (or completely remove the module option).

The second option is to add settings for ts-node:

You can keep "module": "ESNext" for tsc, and if you use webpack, or another build tool, set an override for ts-node. ts-node config

{
  "compilerOptions": {
    "module": "ESNext",
  },
  "ts-node": {
    "compilerOptions": {
      "module": "CommonJS"
    }
  }
}

The third option is to install the tsconfig-paths package:

npm install --save-dev tsconfig-paths

And create a separate TypeScript configuration specifically for your webpack configs:

tsconfig-for-webpack-config.json

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es5",
    "esModuleInterop": true
  }
}

Then set the environment variable process.env.TS_NODE_PROJECT provided by tsconfig-paths like so:

package.json

{
  "scripts": {
    "build": "cross-env TS_NODE_PROJECT=\"tsconfig-for-webpack-config.json\" webpack"
  }
}

CoffeeScript

Similarly, to use CoffeeScript, you would first install the necessary dependencies:

npm install --save-dev coffeescript

and then proceed to write your configuration:

webpack.config.coffee

HtmlWebpackPlugin = require('html-webpack-plugin')
webpack = require('webpack')
path = require('path')

config =
  mode: 'production'
  entry: './path/to/my/entry/file.js'
  output:
    path: path.resolve(__dirname, 'dist')
    filename: 'my-first-webpack.bundle.js'
  module: rules: [ {
    test: /\.(js|jsx)$/
    use: 'babel-loader'
  } ]
  plugins: [
    new HtmlWebpackPlugin(template: './src/index.html')
  ]

module.exports = config

Babel and JSX

In the example below JSX (React JavaScript Markup) and Babel are used, to create a JSON configuration that webpack can understand.

Courtesy of Jason Miller

First, install the necessary dependencies:

npm install --save-dev babel-register jsxobj babel-preset-es2015

.babelrc

{
  "presets": ["es2015"]
}

webpack.config.babel.js

import jsxobj from 'jsxobj';

// example of an imported plugin
const CustomPlugin = (config) => ({
  ...config,
  name: 'custom-plugin',
});

export default (
  <webpack target="web" watch mode="production">
    <entry path="src/index.js" />
    <resolve>
      <alias
        {...{
          react: 'preact-compat',
          'react-dom': 'preact-compat',
        }}
      />
    </resolve>
    <plugins>
      <CustomPlugin foo="bar" />
    </plugins>
  </webpack>
);

Configuration Types

Besides exporting a single configuration object, there are a few more ways that cover other needs as well.

Exporting a Function

Eventually you will find the need to disambiguate in your webpack.config.js between development and production builds. There are multiple ways to do that. One option is to export a function from your webpack configuration instead of exporting an object. The function will be invoked with two arguments:

-module.exports = {
+module.exports = function(env, argv) {
+  return {
+    mode: env.production ? 'production' : 'development',
+    devtool: env.production ? 'source-map' : 'eval',
     plugins: [
       new TerserPlugin({
         terserOptions: {
+          compress: argv.mode === 'production' // only if `--mode production` was passed
         }
       })
     ]
+  };
};

Exporting a Promise

Webpack will run the function exported by the configuration file and wait for a Promise to be returned. Handy when you need to asynchronously load configuration variables.

module.exports = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({
        entry: './app.js',
        /* ... */
      });
    }, 5000);
  });
};

Exporting multiple configurations

Instead of exporting a single configuration object/function, you may export multiple configurations (multiple functions are supported since webpack 3.1.0). When running webpack, all configurations are built. For instance, this is useful for bundling a library for multiple targets such as AMD and CommonJS:

module.exports = [
  {
    output: {
      filename: './dist-amd.js',
      libraryTarget: 'amd',
    },
    name: 'amd',
    entry: './app.js',
    mode: 'production',
  },
  {
    output: {
      filename: './dist-commonjs.js',
      libraryTarget: 'commonjs',
    },
    name: 'commonjs',
    entry: './app.js',
    mode: 'production',
  },
];

dependencies

In case you have a configuration that depends on the output of another configuration, you can specify a list of dependencies using the dependencies array.

webpack.config.js

module.exports = [
  {
    name: 'client',
    target: 'web',
    // …
  },
  {
    name: 'server',
    target: 'node',
    dependencies: ['client'],
  },
];

parallelism

In case you export multiple configurations, you can use the parallelism option on the configuration array to specify the maximum number of compilers that will compile in parallel.

  • Type: number
  • Available: 5.22.0+

webpack.config.js

module.exports = [
  {
    //config-1
  },
  {
    //config-2
  },
];
module.exports.parallelism = 1;

Entry and Context

The entry object is where webpack looks to start building the bundle. The context is an absolute string to the directory that contains the entry files.

context

string

The base directory, an absolute path, for resolving entry points and loaders from the configuration.

const path = require('path');

module.exports = {
  //...
  context: path.resolve(__dirname, 'app'),
};

By default, the current working directory of Node.js is used, but it's recommended to pass a value in your configuration. This makes your configuration independent from CWD (current working directory).


entry

string [string] object = { string | [string] | object = { import string | [string], dependOn string | [string], filename string, layer string, runtime string | false }} (function() => string | [string] | object = { string | [string] } | object = { import string | [string], dependOn string | [string], filename string, layer string, runtime string | false })

The point or points where to start the application bundling process. If an array is passed then all items will be processed.

A dynamically loaded module is not an entry point.

A rule to consider: one entry point per HTML page. SPA: one entry point, MPA: multiple entry points.

module.exports = {
  //...
  entry: {
    home: './home.js',
    about: './about.js',
    contact: './contact.js',
  },
};

Naming

If a string or array of strings is passed, the chunk is named main. If an object is passed, each key is the name of a chunk, and the value describes the entry point for the chunk.

Entry descriptor

If an object is passed the value might be a string, array of strings, or a descriptor:

module.exports = {
  //...
  entry: {
    home: './home.js',
    shared: ['react', 'react-dom', 'redux', 'react-redux'],
    catalog: {
      import: './catalog.js',
      filename: 'pages/catalog.js',
      dependOn: 'shared',
      chunkLoading: false, // Disable chunks that are loaded on demand and put everything in the main chunk.
    },
    personal: {
      import: './personal.js',
      filename: 'pages/personal.js',
      dependOn: 'shared',
      chunkLoading: 'jsonp',
      asyncChunks: true, // Create async chunks that are loaded on demand.
      layer: 'name of layer', // set the layer for an entry point
    },
  },
};

Descriptor syntax might be used to pass additional options to an entry point.

Output filename

By default, the output filename for the entry chunk is extracted from output.filename but you can specify a custom output filename for a specific entry:

module.exports = {
  //...
  entry: {
    app: './app.js',
    home: { import: './contact.js', filename: 'pages/[name].js' },
    about: { import: './about.js', filename: 'pages/[name].js' },
  },
};

Descriptor syntax was used here to pass filename-option to the specific entry points.

Dependencies

By default, every entry chunk stores all the modules that it uses. With dependOn option you can share the modules from one entry chunk to another:

module.exports = {
  //...
  entry: {
    app: { import: './app.js', dependOn: 'react-vendors' },
    'react-vendors': ['react', 'react-dom', 'prop-types'],
  },
};

The app chunk will not contain the modules that react-vendors have.

dependOn option can also accept an array of strings:

module.exports = {
  //...
  entry: {
    moment: { import: 'moment-mini', runtime: 'runtime' },
    reactvendors: { import: ['react', 'react-dom'], runtime: 'runtime' },
    testapp: {
      import: './wwwroot/component/TestApp.tsx',
      dependOn: ['reactvendors', 'moment'],
    },
  },
};

Also, you can specify multiple files per entry using an array:

module.exports = {
  //...
  entry: {
    app: { import: ['./app.js', './app2.js'], dependOn: 'react-vendors' },
    'react-vendors': ['react', 'react-dom', 'prop-types'],
  },
};

Dynamic entry

If a function is passed then it will be invoked on every make event.

Note that the make event triggers when webpack starts and for every invalidation when watching for file changes.

module.exports = {
  //...
  entry: () => './demo',
};

or

module.exports = {
  //...
  entry: () => new Promise((resolve) => resolve(['./demo', './demo2'])),
};

For example: you can use dynamic entries to get the actual entries from an external source (remote server, file system content or database):

webpack.config.js

module.exports = {
  entry() {
    return fetchPathsFromSomeExternalSource(); // returns a promise that will be resolved with something like ['src/main-layout.js', 'src/admin-layout.js']
  },
};

When combining with the output.library option: If an array is passed only the last item is exported.

Runtime chunk

It allows setting the runtime chunk for an entry point and setting it to false to avoid a new runtime chunk since webpack v5.43.0.

optimization.runtimeChunk allows setting it globally for unspecified entry points.

module.exports = {
  //...
  entry: {
    home: {
      import: './home.js',
      runtime: 'home-runtime',
    },
    about: {
      import: './about.js',
      runtime: false,
    },
  },
};

Mode

Providing the mode configuration option tells webpack to use its built-in optimizations accordingly.

string = 'production': 'none' | 'development' | 'production'

Usage

Provide the mode option in the config:

module.exports = {
  mode: 'development',
};

or pass it as a CLI argument:

webpack --mode=development

The following string values are supported:

OptionDescription
developmentSets process.env.NODE_ENV on DefinePlugin to value development. Enables useful names for modules and chunks.
productionSets process.env.NODE_ENV on DefinePlugin to value production. Enables deterministic mangled names for modules and chunks, FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin and TerserPlugin.
noneOpts out of any default optimization options

If not set, webpack sets production as the default value for mode.

Mode: development

// webpack.development.config.js
module.exports = {
  mode: 'development',
};

Mode: production

// webpack.production.config.js
module.exports = {
  mode: 'production',
};

Mode: none

// webpack.custom.config.js
module.exports = {
  mode: 'none',
};

If you want to change the behavior according to the mode variable inside the webpack.config.js, you have to export a function instead of an object:

var config = {
  entry: './app.js',
  //...
};

module.exports = (env, argv) => {
  if (argv.mode === 'development') {
    config.devtool = 'source-map';
  }

  if (argv.mode === 'production') {
    //...
  }

  return config;
};

Output

The top-level output key contains a set of options instructing webpack on how and where it should output your bundles, assets, and anything else you bundle or load with webpack.

output.assetModuleFilename

string = '[hash][ext][query]' function (pathData, assetInfo) => string

The same as output.filename but for Asset Modules.

[name], [file], [query], [fragment], [base], and [path] are set to an empty string for the assets built from data URI replacements.

output.asyncChunks

boolean = true

Create async chunks that are loaded on demand.

webpack.config.js

module.exports = {
  //...
  output: {
    //...
    asyncChunks: true,
  },
};

output.auxiliaryComment

string object

When used in tandem with output.library and output.libraryTarget, this option allows users to insert comments within the export wrapper. To insert the same comment for each libraryTarget type, set auxiliaryComment to a string:

webpack.config.js

module.exports = {
  //...
  output: {
    library: 'someLibName',
    libraryTarget: 'umd',
    filename: 'someLibName.js',
    auxiliaryComment: 'Test Comment',
  },
};

which will yield the following:

someLibName.js

(function webpackUniversalModuleDefinition(root, factory) {
  // Test Comment
  if (typeof exports === 'object' && typeof module === 'object')
    module.exports = factory(require('lodash'));
  // Test Comment
  else if (typeof define === 'function' && define.amd)
    define(['lodash'], factory);
  // Test Comment
  else if (typeof exports === 'object')
    exports['someLibName'] = factory(require('lodash'));
  // Test Comment
  else root['someLibName'] = factory(root['_']);
})(this, function (__WEBPACK_EXTERNAL_MODULE_1__) {
  // ...
});

For fine-grained control over each libraryTarget comment, pass an object:

webpack.config.js

module.exports = {
  //...
  output: {
    //...
    auxiliaryComment: {
      root: 'Root Comment',
      commonjs: 'CommonJS Comment',
      commonjs2: 'CommonJS2 Comment',
      amd: 'AMD Comment',
    },
  },
};

output.charset

boolean = true

Tells webpack to add charset="utf-8" to the HTML