🪓 How to split dev/prod webpack configuration
Francesco Di Donato
Posted on August 2, 2020
🤔 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
📦 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.
-
webpack.common.js
- fixed chunk, whose instructions are necessary both in development and production phase -
webpack.development.js
- merged to the previous in response tonpm start
-
webpack.production.js
- merged to common chunk in response tonpm 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"
},
...
}
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:
- location of the entries point.
- where to create the outcome of the process - but not the naming of chunks since it depends on the environment.
- 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',
}),
],
};
webpack.development.js
In this block we are going to provide a set of instructions needed in developing.
- For the sake of simplicity I chose only one plugin, system-bell-webpack-plugin.
- Since webpack-dev-server allocates the outcome in memory, I do not need any hash to filenames.
- 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]
};
webpack.production.js
Same concept as above - here we got the instructions needed for obtain a production-ready dist.
- 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.
- 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]
};
All that's left is to enable webpack.config.js
to merge what we just created.
webpack.config.js
- Import the package webpack-merge
- if needed, download it via
npm i -D webpack-merge
- if needed, download it via
- Since it's always used, import the common chunk.
- 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'.
- the dynamism of this operation can be obtained in several ways. The simplest implementation is the use of an
- 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]
};
😎 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
Posted on August 2, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.