DEV Community

Cover image for ☯ Intuitive dev/prod webpack configuration
Francesco Di Donato
Francesco Di Donato

Posted on

☯ Intuitive dev/prod webpack configuration

πŸ€” Use Case

You want to provide webpack with a different configuration based on the environment variable.
By directly adding the instruction pairs in the configuration file with a monolithic model, you risk a headhache 😡. There must be some way to make it simpler.

πŸ“œ Example Code

intuitive-webpack-config

πŸ“¦ Packages


πŸ’‘ Solution

This is not πŸš€-science - it is about the order and the benefits deriving from it. I unpack the main configuration file by placing the instruction sets into appropriate files. Simply inform webpack of the environment variable (env) and it will know how to derive the appropriate orders.

Even from the developer’s point of view it becomes easier to follow the logical thread of the program, maybe even after a long time.

πŸ€“ Implementing the Solution

Initial State:

  • package.json (npm init -y)
  • src/index.js (content not relevant)
  • config

  • [1] Add packages
  • [2] Add npm scripts to package.json
  • [3] Building components
  • [4] Assembling components

- 1 - Add packages

In the terminal invoke: npm i -D webpack webpack-cli webpack-dev-server

- 2 - Add npm scripts to package.json

Update package.json adding the start and the build scripts. In the first case we use the development server specifying that env is development.
The alternative is the use of the bundler in production mode.

{
 ...
 "scripts": {
    "start": "webpack-dev-server --env development",
    "build": "webpack --env production"
  },
 ...
}
Enter fullscreen mode Exit fullscreen mode

- 3 - Building components | 🦿 usePlugins

To pull up a wall first you have to make the bricks. This will be able to return a different array based on env as well as allowing easy and quick integration of plugins addition.

Create usePlugins.js in config. This file is structured like so:

  • plugins imports
  • exported function
    • configuration panel 🎚
    • business logic βš™
// plugins imports
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

// exported function
exports.usePlugins = (e) => {

    // configuration panel
    const pluginsPanel = {
        development: 'html',
        production: 'html clean',
        values: {
            html: new HtmlWebpackPlugin({
                title: 'Webpack Loading CSS',
            }),
            clean: new CleanWebpackPlugin(),
        },
    };

    // business logic
    let message = '[plugins]: ';
    let error = '';

    const plugins = pluginsPanel[e.toString()];
    const arr = plugins.split(' ');

    const outcome = arr
        .map((plugin) => {
            const p = pluginsPanel.values[plugin];
            if (!p) {
                error += plugin + ' ';
                return;
            }
            message += plugin + ' '
            return p;
        })
        .filter((plugin) => typeof plugin !== 'undefined');

    console.info(message);
    console.warn('[plugins|error]: ' + (error !== '' ? error : 'none'));
    return outcome;
};

Enter fullscreen mode Exit fullscreen mode

As you will appreciate in the end all the cumbersome import of plugins are in this secondary file, while webpack.config.js will report only the essentials.
In the configuration panel are specified two different sets containing labels - all real plugin builders are crammed into a container (.values).
The exported function receives the env and according to it selects the right set.
It’s up to the business logic to read the label, to understand if the relative plugin is present into the said container and if so place it in the final product.

Optionally it is best to sanitize the final result by filtering away the plugins not found and showing an error message

- 3 - Building components | β›“ index

If you plan to expand this technique on later occasions it becomes useful to have to opportunity to get all these components with a single import.
In config folder add an index.js file.

const { usePlugins } = require('./usePlugins');
// const { anotherPlugin } = require('./another');

module.exports = {
   usePlugins,
   // anotherPlugin
};
Enter fullscreen mode Exit fullscreen mode

The utility of this practice is more visible as the number of plugins grows.


- 4 - Assembling components πŸ”§

It’s time to connect the wires in webpack.config.js.

const path = require('path');
const helpers = require('./config'); //[1]

module.exports = (env) => ({ //[2]
    entry: {
        main: './src/index.js',
    },
    output: {
        path: path.join(__dirname, 'dist'),
        filename: '[name].js',
    },
    plugins: helpers.usePlugins(env),
});
Enter fullscreen mode Exit fullscreen mode
  1. When you require the contents of a folder rather than a specific file contained in it, is selected by default the file named index.
  2. Rather than returning a configuration object directly, a function is exported - it can accept the env variable and use it to generate the appropriate outcome.

😎 Checking the Outcome

Try to assign different plugin combinations in the control panel and compare expectations with the message received at the console. Then try to make up some funny plugin label and add it - the server/build process will not crack and in the console is reported the culprit.

Check the example code for other use cases.

Top comments (0)