loading...
Cover image for 🪓 How to split dev/prod webpack configuration

🪓 How to split dev/prod webpack configuration

didof profile image Francesco Di Donato Updated on ・3 min read

🤔 Use Case

As the your project grows also the size of configuration increases. If to this is added the need for a different webpack behavior based on the environment it becomes clear that a monolithic configuration is no longer optimal.

📜 Example Code

webpack-configuration-split

📦 Packages


💡 Solution

Levaraging the fact that webpack uses a JavaScript file as a configuration, we can break it down into three blocks that we can merge according to the environment.

  1. webpack.common.js - fixed chunk, whose instructions are necessary both in development and production phase
  2. webpack.development.js - merged to the previous in response to npm start
  3. webpack.production.js - merged to common chunk in response to npm run build

🤓 Implementing the Solution

Initial State:

  • src/index.js
  • webpack.config.js
  • package.json

package.json

Before writing the configuration, I set the npm scripts specifying the different environment variables.

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

Now I am going to create the three partial configuration and group them in a special folder named config.

webpack.common.js

The following instructions are common in both cases:

  1. location of the entries point.
  2. where to create the outcome of the process - but not the naming of chunks since it depends on the environment.
  3. generate the HTML index file.
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: { //[1]
        main: './src/index.js'
    },
    output: { //[2]
        path: path.join(__dirname, '..', 'dist')
    },
    plugins: [ //[3]
        new HtmlWebpackPlugin({
            title: 'Webpack Configuration Split',
        }),
    ],
};
Enter fullscreen mode Exit fullscreen mode

webpack.development.js

In this block we are going to provide a set of instructions needed in developing.

  1. For the sake of simplicity I chose only one plugin, system-bell-webpack-plugin.
  2. Since webpack-dev-server allocates the outcome in memory, I do not need any hash to filenames.
  3. It makes sense to provide instructions for the devolpment server only when it is actually used.
const SystemBellPlugin = require('system-bell-webpack-plugin');

module.exports = {
    output: {
        filename: '[name].js', //[2]
    },
    devServer: { //[3]
        compress: false,
        open: 'chrome',
        stats: 'errors-only',
        overlay: true,
    },
    plugins: [new SystemBellPlugin()], //[1]
};
Enter fullscreen mode Exit fullscreen mode

webpack.production.js

Same concept as above - here we got the instructions needed for obtain a production-ready dist.

  1. To prevent the caching of the bundles (or any other file) by the browser, a simple solution is to associate a hash within the filenames.
  2. Once again for simplicity, I show only one basic plugin [2]
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
   output: {
      filename: '[name].[hash].js' //[1]
   },
    plugins: [new CleanWebpackPlugin()], //[2]
};
Enter fullscreen mode Exit fullscreen mode

All that's left is to enable webpack.config.js to merge what we just created.

webpack.config.js

  1. Import the package webpack-merge
    • if needed, download it via npm i -D webpack-merge
  2. Since it's always used, import the common chunk.
  3. Differently, import only the required chunk based on the environment.
    • the dynamism of this operation can be obtained in several ways. The simplest implementation is the use of an if(env == 'development'). The example I reported, although more streamlined, requires that the variable env (which we will declare shortly) must be 'development' or 'production'.
  4. Finally, use merge on the fixed configuration and the dynamically imported one.
const { merge } = require('webpack-merge'); //[1]

const commonConfig = require('./config/webpack.common'); //[2]

module.exports = (env) => {
    const config = require('./config/webpack.' + env); //[3]
    return merge(commonConfig, config); //[4]
};
Enter fullscreen mode Exit fullscreen mode

😎 Checking the Outcome

npm start - Google Chrome open by itself, open up devTools and reach Network section. Reload the page and check the chunk name.
npm run build - peek in the oven-fresh dist folder, see the hashed name? Try to modify index.js, run the script again to visualize that in fact you are using the plugin only offered by the production configuration file.

❣ More Details surviveJS

Discussion

pic
Editor guide