Apr 17, 2020 · 3min to read
A brief note on how to adjust Gatsby’s default webpack config to apply custom cssnano optimizations
Gatsby is an open-source, React-based, static site generator. It combines modern JS development environment, rich React ecosystem, and high performance into enjoyable developer experience. I use Gatsby in two projects, and I am happy with it.
Gatsby lets you create fast sites out-of-the-box by automatically applying various performance optimizations and improvements under the hood. While most of the optimizations work well, some of them might require additional tweaking.
We’ll touch upon CSS compression. It takes place during bundle compilation in webpack - one of Gatsby’s core packages. Handled by optimize-css-assets-webpack-plugin’s default CSS processor - cssnano, it occurs only for a production build.
During development, your site will work as expected, but once you switch to a production environment, it might behave unexpectedly:
Notice how the main heading is not changing its size when resizing the screen on production. The cause of it lies in the default cssnano config, which has buggy calc optimization turned on by default.
As a workaround, one can disable the calc()
optimization. But how can we achieve this in Gatsby?
Luckily there is a Node API called onCreateWebpackConfig
, allowing us to change the existing configuration. Gatsby does multiple webpack builds with different configs; they call these stages. We need to target build-javascript
stage - that’s where production bundles are being built. Inspecting Gatsby’s webpack.config.js reveals that the CSS optimization plugin is located inside optimization.minimizer
array. Now we are ready to alter default cssnano options.
Here is what you need to add to your gatsby-node.js:
jsjs
exports.onCreateWebpackConfig = ({actions,stage,plugins,getConfig}) => {// override config only during// production JS & CSS buildif (stage === 'build-javascript') {// get current webpack configconst config = getConfig()// our new cssnano options// are still based on default presetconst options = {cssProcessorPluginOptions: {preset: ['default',{discardComments: {removeAll: true},calc: false,reduceTransforms: false,minifySelectors: false}]}}// find CSS minimizerconst minifyCssIndex = config.optimization.minimizer.findIndex(minimizer => minimizer.constructor.name ==='OptimizeCssAssetsWebpackPlugin')// if found, overwrite existing CSS minimizer with the new oneif (minifyCssIndex > -1) {config.optimization.minimizer[minifyCssIndex] =plugins.minifyCss(options)}// replace webpack config with the modified objectactions.replaceWebpackConfig(config)}}
Besides disabling calc, I’ve also switched off minifySelectors and reduceTransforms as they both were messing up my CSS in the past, but your mileage may vary. Now we can create new production build and test it out.
Our CSS behaves as expected again.