Splitting the Configuration
At minimum, your Webpack configuration can be contained in a single file. As the needs of your project grow, you'll need to figure out means to manage it. It becomes necessary to split it up per environment so that you have enough control over the build result. There is no single right way to achieve this, but at least the following ways are feasible:
- Maintain configuration in multiple files and point Webpack to each through
--config
parameter. Share configuration through module imports. You can see this approach in action at webpack/react-starter. - Push configuration to a library which you then consume. Example: HenrikJoreteg/hjs-webpack.
- Maintain configuration within a single file and branch there. If we trigger a script through npm (i.e.,
npm run test
), npm sets this information in an environment variable. We can match against it and return the configuration we want.
I prefer the last approach as it allows me to understand what's going on easily. I've developed a little tool known as webpack-merge to achieve this. I'll show you how to set it up next.
Setting Up webpack-merge
To get started, execute
npm i webpack-merge --save-dev
to add webpack-merge to the project.
Next, we need to define some split points to our configuration so we can customize it per npm script. Here's the basic idea:
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
leanpub-start-insert
const merge = require('webpack-merge');
leanpub-end-insert
const PATHS = {
app: path.join(__dirname, 'app'),
build: path.join(__dirname, 'build')
};
leanpub-start-delete
module.exports = {
leanpub-end-delete
leanpub-start-insert
const common = {
leanpub-end-insert
// Entry accepts a path or an object of entries.
// We'll be using the latter form given it's
// convenient with more complex configurations.
entry: {
app: PATHS.app
},
output: {
path: PATHS.build,
filename: '[name].js'
},
plugins: [
new HtmlWebpackPlugin({
title: 'Webpack demo'
})
]
};
leanpub-start-insert
var config;
// Detect how npm is run and branch based on that
switch(process.env.npm_lifecycle_event) {
case 'build':
config = merge(common, {});
break;
default:
config = merge(common, {});
}
module.exports = config;
leanpub-end-insert
After this change our build should behave exactly the same way as before. This time, however, we have room for expansion. We can hook up Hot Module Replacement in the next chapter to make the browser refresh and turn our the development mode into something more useful.
Integrating webpack-validator
To make it easier to develop our configuration, we can integrate a tool known as webpack-validator to our project. It will validate the configuration against a schema and warn if we are trying to do something not sensible. This takes some pain out of learning and using Webpack.
Install it first:
npm i webpack-validator --save-dev
Integrating it to our project is straight-forward:
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const merge = require('webpack-merge');
leanpub-start-insert
const validate = require('webpack-validator');
leanpub-end-insert
...
leanpub-start-delete
module.exports = config;
leanpub-end-delete
leanpub-start-insert
module.exports = validate(config);
leanpub-end-insert
If you break your Webpack configuration somehow after doing this, the validator will likely notice and give you a nice validation error to fix.
Conclusion
Even though a simple technique, splitting configuration this way makes room for growing your setup. Each approach comes with its pros and cons. I find this one works well for small to medium projects. Bigger projects might need a different approach.
Now that we have room for growth, I will show you how to set up automatic browser refresh with Webpack in the next chapter.