# Configure for development

To configure webpack for a development environment, execute the following steps.

# Install the packages

Open a terminal at the root of the project and install the following packages:

pnpm add -D @workleap/webpack-configs webpack webpack-cli webpack-dev-server @swc/core @swc/helpers browserslist postcss nodemon
yarn add -D @workleap/webpack-configs webpack webpack-cli webpack-dev-server @swc/core @swc/helpers browserslist postcss nodemon
npm install -D @workleap/webpack-configs webpack webpack-cli webpack-dev-server @swc/core @swc/helpers browserslist postcss nodemon

# Configure webpack

# HTML template

First, create a public folder with an index.html file at the root of the project:

web-project
├── public
├──── index.html
├── src
├──── ...
├── package.json

Then, open the newly created index.html file and copy/paste the following content:

public/index.html
<!DOCTYPE html>
<html>
    <head>
    </head>
    <body>
        <div id="root"></div>
    </body>
</html>

The content of the public/index.html file is the default template that will be used by HtmlWebpackPlugin.

# Reference local assets

To reference local assets such as a favicon.png in the default HTML template, it is recommended to preprend the relative path of every asset with the publicPath of the webpack config.

First, add the asset to the public folder at the root of the project:

web-project
├── public
├──── index.html
├──── favicon.png
├── src
├──── ...
├── package.json

Then, add the assets to the index.html file:

public/index.html
<!DOCTYPE html>
<html>
    <head>
        <link href="<%=webpackConfig.output.publicPath%>favicon.png" rel="icon">
    </head>
    <body>
        <div id="root"></div>
    </body>
</html>

# defineDevConfig

Next, create a configuration file named webpack.dev.js at the root of the project:

web-project
├── public
├──── index.html
├── src
├──── ...
├── package.json
├── webpack.dev.js

Then, open the newly created file and export the webpack configuration by using the defineDevConfig(swcConfig, options) function:

webpack.dev.js
// @ts-check

import { defineDevConfig } from "@workleap/webpack-configs";
import { swcConfig } from "./swc.dev.js";

export default defineDevConfig(swcConfig);

# swcConfig

In the previous code sample, the defineDevConfig(swcConfig, options) function receive an SWC configuration object through the swcConfig parameter.

Although the swc-loader defaults to loading the closest .swcrc configuration file when no configuration object is provided, it lacks support for distinct configuration files by environment like webpack does.

Therefore, @workleap/webpack-configs choosed to delegate the loading of the SWC configuration to the consumer by making the swcConfig option required.

# Use predefined options

The defineDevConfig(swcConfig, options) function can be used as shown in the previous example, however, if you wish to customize the default configuration, the function also accept a few predefined options to help with that 👇

# entry

  • Type: string
  • Default: ./src/index.tsx

Set webpack entry option.

webpack.dev.js
// @ts-check

import { defineDevConfig } from "@workleap/webpack-configs";
import { swcConfig } from "./swc.dev.js";

export default defineDevConfig(swcConfig, {
    entry: "./src/another-entry.tsx"
});

# https

  • Type: boolean | ServerOptions
  • Default: false

Set webpack DevServer https option and format webpack publicPath option accordingly.

webpack.dev.js
// @ts-check

import { defineDevConfig } from "@workleap/webpack-configs";
import { swcConfig } from "./swc.dev.js";

export default defineDevConfig(swcConfig, {
    https: true
});

# host

  • Type: string
  • Default: localhost

Set webpack DevServer host option and format webpack publicPath option accordingly.

webpack.dev.js
// @ts-check

import { defineDevConfig } from "@workleap/webpack-configs";
import { swcConfig } from "./swc.dev.js";

export default defineDevConfig(swcConfig, {
    host: "my-custom-host"
});

# port

  • Type: number
  • Default: 8080

Set webpack DevServer port option and format webpack publicPath option accordingly.

webpack.dev.js
// @ts-check

import { defineDevConfig } from "@workleap/webpack-configs";
import { swcConfig } from "./swc.dev.js";

export default defineDevConfig(swcConfig, {
    port: 1234
});

# publicPath

  • Type: boolean
  • Default: ${https ? "https" : "http"}://${host}:${port}/

Set webpack public path.

webpack.dev.js
// @ts-check

import { defineDevConfig } from "@workleap/webpack-configs";
import { swcConfig } from "./swc.dev.js";

export default defineDevConfig(swcConfig, {
    // The ending "/" is very important.
    publicPath: "http://dev-host:8080/"
});

Or for an automatic public path:

webpack.build.js
// @ts-check

import { defineDevConfig, defineDevHtmlWebpackPluginConfig  } from "@workleap/webpack-configs";
import { swcConfig } from "./swc.dev.js";

export default defineDevConfig(swcConfig, {
    publicPath: "auto",
    // If you are using the html webpack plugin, make sure to also set the plugin
    // public path option to "/".
    htmlWebpackPlugin: defineDevHtmlWebpackPluginConfig({
        publicPath: "/"
    })
});

# cache

  • Type: boolean
  • Default: true

Whether or not webpack memory cache is enabled. This will also set maxGenerations to 1 to remove cache entries from memory when they are no longer needed.

webpack.dev.js
// @ts-check

import { defineDevConfig } from "@workleap/webpack-configs";
import { swcConfig } from "./swc.dev.js";

export default defineDevConfig(swcConfig, {
    cache: false
});

# moduleRules

  • Type: An array of webpack moduleRule objects
  • Default: []

Append the provided webpack module rules to the configuration.

webpack.dev.js
// @ts-check

import { defineDevConfig } from "@workleap/webpack-configs";
import { swcConfig } from "./swc.dev.js";

export default defineDevConfig(swcConfig, {
    moduleRules: [
        {
            test: /\.s[ac]ss$/i,
            use: ["style-loader", "css-loader", "sass-loader"]
        }
    ]
});

# plugins

Append the provided webpack plugins to the configuration.

webpack.dev.js
// @ts-check

import { defineDevConfig } from "@workleap/webpack-configs";
import { swcConfig } from "./swc.dev.js";
import CircularDependencyPlugin from "circular-dependency-plugin";

export default defineDevConfig(swcConfig, {
    plugins: [
        new CircularDependencyPlugin({
            exclude: /node_modules/,
            include: /src/
        });
    ]
});

# htmlWebpackPlugin

  • Type: boolean or an object literal accepting any html-webpack-plugin option
  • Default: { template: "./public/index.html" }

To remove the default instance of html-webpack-plugin, set the property to false.

webpack.dev.js
// @ts-check

import { defineDevConfig } from "@workleap/webpack-configs";
import { swcConfig } from "./swc.dev.js";

export default defineDevConfig(swcConfig, {
    htmlWebpackPlugin: false
});

To extend/replace the default html-webpack-plugin configuration, use the defineDevHtmlWebpackPluginConfig(options) function.

webpack.dev.js
// @ts-check

import { defineDevConfig, defineDevHtmlWebpackPluginConfig } from "@workleap/webpack-configs";
import { swcConfig } from "./swc.dev.js";
import path from "path";

export default defineDevConfig(swcConfig, {
    htmlWebpackPlugin: defineDevHtmlWebpackPluginConfig({
        template: path.resolve("./my-custom-index.html"),
        minify: true
    })
});

# fastRefresh

  • Type: boolean or an object literal accepting any react-refresh-webpack-plugin option
  • Default: true

Replace webpack HMR by Fast Refresh. Desactivating webpack fast refresh will automatically disable fast refresh for SWC.

webpack.dev.js
// @ts-check

import { defineDevConfig } from "@workleap/webpack-configs";
import { swcConfig } from "./swc.dev.js";

export default defineDevConfig(swcConfig, {
    fastRefresh: false
});

To extend/replace the default Fast Refresh configuration, use the defineFastRefreshPluginConfig(options) function.

webpack.dev.js
// @ts-check

import { defineDevConfig, defineFastRefreshPluginConfig } from "@workleap/webpack-configs";
import { swcConfig } from "./swc.dev.js";

export default defineDevConfig(swcConfig, {
    fastRefresh: defineFastRefreshPluginConfig({ overlay: false })
});
  • options: An object literal accepting any react-refresh-webpack-plugin option

# cssModules

  • Type: boolean
  • Default: false

Enable css-loader modules feature.

webpack.dev.js
// @ts-check

import { defineDevConfig } from "@workleap/webpack-configs";
import { swcConfig } from "./swc.dev.js";

export default defineDevConfig(swcConfig, {
    cssModules: true
});

# overlay

  • Type: false
  • Default: undefined

Whether or not a full-screen overlay should be in the browser when there are compiler errors or warnings.

webpack.dev.js
// @ts-check

import { defineDevConfig } from "@workleap/webpack-configs";
import { swcConfig } from "./swc.dev.js";

export default defineDevConfig(swcConfig, {
    overlay: false
});

# svgr

  • Type: boolean or an object literal accepting any @svgr/webpack option
  • Default: true

Whether or not to handle .svg files with @svgr/webpack. If @svgr/webpack is desactived, the .svg files will are handled by the asset/resource rule.

webpack.dev.js
// @ts-check

import { defineDevConfig } from "@workleap/webpack-configs";
import { swcConfig } from "./swc.dev.js";

export default defineDevConfig(swcConfig, {
    svgr: false
});

To extends the @svgr/webpack rule configuration, provide an object literal instead.

webpack.dev.js
// @ts-check

import { defineDevConfig } from "@workleap/webpack-configs";
import { swcConfig } from "./swc.dev.js";

export default defineDevConfig(swcConfig, {
    svgr: {
        ref: true
    }
});

# verbose

  • Type: boolean
  • Default: false

Start the webpack process with verbose logging turned on.

webpack.dev.js
// @ts-check

import { defineDevConfig } from "@workleap/webpack-configs";
import { swcConfig } from "./swc.dev.js";

export default defineDevConfig(swcConfig, {
    verbose: true
});

# Configuration transformers

The predefined options are useful to quickly customize the default development configuration of @workleap/webpack-configs, but only covers a subset of a webpack configuration. If you need full control over the configuration, you can provide configuration transformer functions through the transformers option of the defineDevConfig function. Remember, no locked in ❤️✌️.

To view the default development configuration of @workleap/webpack-configs, have a look at the dev.ts configuration file on GitHub.

# transformers

  • Type: ((config: WebpackConfig, context: WebpackConfigTransformerContext) => WebpackConfig)[]
  • Default: []
transformer(config: WebpackConfig, context: WebpackConfigTransformerContext) => WebpackConfig
webpack.dev.js
// @ts-check

import { defineDevConfig } from "@workleap/webpack-configs";
import { swcConfig } from "./swc.dev.js";

/**
 * @type {import("@workleap/webpack-configs").WebpackConfigTransformer}
 */
function enableInMemoryCache(config) {
    config.cache = {
        type: "memory"
    };

    return config;
};

export default defineDevConfig(swcConfig, {
    cache: false,
    transformers: [enableInMemoryCache]
});

# Execution context

Generic transformers can use the context parameter to gather additional information about their execution context, like the environment they are operating in:

transformer.js
// @ts-check

/**
 * @type {import("@workleap/webpack-configs").WebpackConfigTransformer}
 */
export function transformer(config, context) {
    if (context.environment === "dev") {
        config.cache = {
            type: "memory"
        };
    }

    return config;
};
  • environment: "dev" | "build"
  • verbose: boolean

# Utilities

Modifying a webpack configuration object can be an arduous task, to help with that, @workleap/webpack-configs offer utility functions for modules rules and plugins.

Transformer utilities
../transformer-utilities/

# Setup nodemon

Nodemon is a utility that will monitor for any changes in the swc.dev.js and webpack.dev.dev.js files and restart the webpack development server whenever a change occurs.

First, add a nodemon.json file at the root of the project:

web-project
├── public
├──── index.html
├── src
├──── ...
├── package.json
├── webpack.dev.js
├── nodemon.json

Then, open the nodemon.json file and copy/paste the following content:

nodemon.json
{
    "watch": ["swc.dev.js", "webpack.dev.js"],
    "exec": "webpack serve --config webpack.dev.js"
}

Finally, add a CLI script at the next step of this guide.

# Add a CLI script

To initiate the development server, add the following script to your project package.json file:

package.json
{
    "dev": "nodemon"
}

# Define environment variables

To deal with environment variables, the webpack documentation suggests using the --env option from its CLI. While that would work, by using webpack --env CLI option, the environment variables would only be made available to the webpack configuration files (.e.g. webpack.dev.js) rather than any Node.js files. Therefore we do not recommend using webpack --env CLI option.

# cross-env

We recommend instead to define environment variables using cross-env. With cross-env, the environment variables will be made available to any Node.js files that are executed by the script process (dev in the example below 👇):

package.json
{
    "dev": "cross-env DEBUG=true nodemon"
}
webpack.dev.js
// @ts-check

import { defineDevConfig } from "@workleap/webpack-configs";
import { swcConfig } from "./swc.dev.js";

if (process.env.DEBUG) {
    console.log("Configuring webpack in debug mode!");
}

export default defineDevConfig(swcConfig);

However, there's a catch. When using cross-env, the variables will not be available in the application files because cross-env only makes them available to files that are executed by the process at build time while the application files are executed at runtime by a browser.

To make them accessible to the application files, webpack must be aware of those environment variables and render them into the compiled application files. This is the purpose of the environmentVariables option.

# environmentVariables

  • Type: Record<string, unknown>
  • Default: {}

First, define the variables with environmentVariables:

webpack.dev.js
// @ts-check

import { defineDevConfig } from "@workleap/webpack-configs";
import { swcConfig } from "./swc.dev.js";

export default defineDevConfig(swcConfig, {
    environmentVariables: {
        "DEBUG": process.env.DEBUG === "true"
    }
});

Then, use the variables in any application files:

src/app.tsx
export function App() {
    if (process.env.DEBUG) {
        console.log("The application has been bootstrapped in debug!");
    }

    return null;
}

# Try it 🚀

To test your new webpack configuration, open a terminal at the root of the project and execute the CLI script added earlier. A development server should start without outputting any error in the terminal.