babel-loader's hidden feature - babelrc:false

💡 This might be out of date - 1 years old 💡

I’ve spent 3 days configuring Webpack and babel to deal with CSS Modules while doing server-side rendering. I’ve just discovered an undocumented setting in Webpack’s babel-loader that solves the mystery of disappearing css.

On the server, I’ve got a .babelrc file which uses babel-plugin-css-modules-transform.

    "presets": ["es2015-node4", "react"],
    "plugins": [
        ["css-modules-transform", {
            "generateScopedName": "[name]__[local]___[hash:base64:5]",
            "extensions": [".styl", ".css"],
            "preprocessCss": "./stylus-require-hook.js"
    "ignore": ["./stylus-require-hook.js"]

On the client side, I’ve got webpack building my code, I’m using the babel-loader to transform my JavaScript and I’ve set up a regex to catch all the .styl files and push them through the stylus loader, then the css loader with the css modules configuration and finally to the style loader.

I could get the server side code to correctly create the hashed module names, but on the client, I couldn’t get Webpack to pick up the stylus file that I created so I could transform it into css modules. I checked out the regex’s multiple times and every other setting I could find. I’d rewritten my Webpack config at least twice from scratch and still I was getting this issue. My build output wouldn’t contain any css files despite using the Extract Text Plugin.

I eventually checked out the javascript created from my build and discovered that it contained a lot of css attribute names and this is when it clicked. My babel-loader config was picking up my server side .babelrc and running my stylus files through the css module transform.

I’d checked the documentation a few times but I couldn’t see anything about the default functionality of picking up the .babelrc file. This is a weird default because we compile to different targets with different features for server and web.

I discovered the settings babelrc: false in one of the github issues and gave it a go. It has to be supplied as an attribute on the query object passed to babel-loader.

It should look like this:

                test: /\.js/,
                exclude: /(node_modules|bower_components)/,
                loader: 'babel',
                query: {
                    babelrc: false,
                    presets: ['es2015', 'react'],
                    plugins: [
                        ['transform-es2015-classes', { loose: true }],

This means that the babel-loader will only use the settings you’ve provided to it in the query object allowing you to have entirely different babel configurations for both client and server.

Written by who lives and works in Sydney building 3D maps in the browser.