Want to learn React? Check out my new course React for Beginners: Build and app, and learn the fundamentals.Want to learn React? Check out my new course React for Beginners: Build and app, and learn the fundamentals.
One webpack config to rule them all — environments that is
Webpack 2 is officially here — and to celebrate I wanted to share some tips on having one webpack config file to handle multiple environments.
There are plenty of examples out there demoing separate webpack.config files for each of your environments e.g. dev, production etc. Personally I prefer to avoid creating multiple files and handle everything in one config file, which I feel really helps simplify things.
Some PROS for single config file
- Much easier to decipher what’s happening in a build when you can look in a single file instead of piecing together many files.
- Avoiding duplication becomes much more straight forward
- Same config is used in all environments — no need to serve different files based on environment.
Ok, so enough of the benefits let’s get to how it’s done. For those who would just rather look at the full config file you can find it on my github.
Getting Started
The first thing we’re going to do is create a bare bones webpack.config.
You will notice that we export a function that returns our config object, and that function takes an env
param. This env
param will be passed in when you run webpack
from the command line. To set the value for env
you use webpack’s new --env.{ value }
flag where value would be the environment you’re targeting.
// Assuming you're using npm scripts in package.json"scripts": {
"build:dev": "webpack --env.dev",
"build:prod": "webpack --env.prod -p"
}
Now that our config file has access to the env
value passed from the command line we can conditionally add logic based on environment. To help with this I use a very helpful module created by Kent C. Dodds called webpack-config-utils.
NOTE: This is a partial webpack.config file created for this demo. To view my complete webpack.config visit my github.
The fist thing I do is setup two convenience methods ifProd, iNotProd
using the getIfUtils
from webpack-config-utils. These two methods can then be used to conditionally return something based on environment.
NOTE: The
getIfUtils
method provides more options thanifProd
andifNotProd
. Have a look at the source to learn more.
// If env === prod then set cache = true, if not set cache = false cache: ifProd()// This would do the reverse of the above
cache: ifNotProd()
The other function we depend on is removeEmpty
— when used in combination with ifProd
and ifNotProd
we gain a lot of flexibility in our config. Config properties like entry
, modules.rules
, and plugins
usually take an array as their value, but if any items in the array are undefined that can cause issues. By wrapping an array in removeEmpty
first all undefined items will be filtered out of the array.
plugins: removeEmpty([
new ProgressBarPlugin(),
ifProd(new webpack.LoaderOptionsPlugin({ minimize: true }))
])
By wrapping our plugins array in removeEmpty
were are able to dynamically add plugins to our array based on environment. In the above example if env === 'prod'
then the webpack.LoaderOptionsPlugin would be added, while the opposite would be true when not prod. This works because ifProd
will return undefined when env !== 'prod’
, and then removeEmpty
would remove this item from the array.
Wrapping Up
Once you have an understanding of how the getIfUtils
and removeEmpty
methods work it’s just really rinse, lather, repeat to add this to other areas of your config file. I do realize this approach may not be for everyone, and that a single file approach could become unruly depending on the complexity of the build. When this becomes the case I still prefer leveraging comments, and whitespace to help organize things rather then busting things into separate files, but this really comes down to personal preference 😉.
Thanks again to Kent C. Dodds for creating these simple but powerful utility functions 💪💪.