babel-loader: .babelrc not working

I have folled a very simple tutorial to set up webpack, babel and react, but get an error with the presets when I use a .babelrc file.

webpack.config.js:

var path = require('path');

module.exports = {
    entry: './src/index.js', // Bundle all assets from this location together
    output: {
        filename: 'bundle.js', // Output to this file
        path: path.resolve( __dirname, 'dist' ) // In this location
    },
    module: {
        rules: [
            { 
                test: /\.(js|jsx|mjs)$/, 
                loader: 'babel-loader',
                exclude: /node_modules/,

            },
            {
                test: /\.css$/,
                use: [ 'style-loader', 'css-loader' ]
            }
        ]
    },
    devServer: {
        contentBase: path.resolve(__dirname, "dist")
    }
};

.babelrc:

{
  "presets": ["env", "react"]
}

Gets me the following error:

ERROR in ./src/index.js
Module build failed: SyntaxError: Unexpected token (17:12)

  15 |     render() {
  16 |         return (
> 17 |             <div style={ { textAlign: 'center' } }>
     |             ^

If I change my webpack.config.js file to this instead it works:

var path = require('path');

module.exports = {
    entry: './src/index.js', // Bundle all assets from this location together
    output: {
        filename: 'bundle.js', // Output to this file
        path: path.resolve( __dirname, 'dist' ) // In this location
    },
    module: {
        rules: [
            { 
                test: /\.(js|jsx|mjs)$/, 
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['env', 'react']
                    }
                }
            },
            {
                test: /\.css$/,
                use: [ 'style-loader', 'css-loader' ]
            }
        ]
    },
    devServer: {
        contentBase: path.resolve(__dirname, "dist")
    }
};

From my understanding having the options object or a .babelrc file should do the same thing. But only one of them works.

I don’t have a "babel": {} block within my package.json so I really don’t see why it seems that the .babelrc file is not recognized.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 21
  • Comments: 36 (7 by maintainers)

Commits related to this issue

Most upvoted comments

I have this code in my .babelrc and its working for me.

  • .babelrc
{
  "presets": ["es2015", "react"]
}

For more, I have my

  • webpack.config.js
const path = require("path");
const webpack = require("webpack");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const extractCSS = new ExtractTextPlugin("semantic/semantic.min.css");

const config = {
  entry: "./app/app.js",
  output: {
    path: path.resolve(__dirname, "public", "js"),
    filename: "bundle.js"
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        loaders: ["babel-loader"],
        exclude: /node_modules/
        // query: {
        //   presets: ["es2015", "react", "stage-0"]
        // }
      },
      {
        test: /\.jsx?$/,
        loaders: ["babel-loader"],

        exclude: /node_modules/
      },
      {
        test: /\.css$/,
        include: /node_modules/,
        use: ExtractTextPlugin.extract({
          fallback: "style-loader",
          use: [
            {
              loader: "css-loader"
            },
            {
              loader: "postcss-loader"
            }
          ]
        })
      },
      {
        test: /\.(png|woff|woff2|eot|ttf|svg)$/,
        loader: "url-loader?limit=100000"
      }
    ]
  },

  plugins: [
    new ExtractTextPlugin("styles.css"),
    new webpack.LoaderOptionsPlugin({
      debug: true
    })
  ]
};

module.exports = config;

and

  • package.json
{
  "name": "electron-react",
  "productName": "Electron React",
  "version": "1.0.0",
  "description": "Electron React",
  "main": "main.js",
  "scripts": {
    "test": "npm test",
    "start": "electron .",
    "electron": "webpack",
    "watch": "watchify app/app.js -t babelify -o public/js/bundle.js --debug --verbose"
  },
  "dependencies": {
    "axios": "^0.9.1",
    "babel-loader": "^7.1.2",
    "babel-preset-es2015": "^6.6.0",
    "babel-preset-react": "^6.5.0",
    "babelify": "^7.2.0",
    "classnames": "^2.2.3",
    "css-loader": "^0.28.9",
    "electron-prebuilt": "^0.36.0",
    "electron-reload": "^0.2.0",
    "extract-text-webpack-plugin": "^3.0.2",
    "file-loader": "^1.1.6",
    "jquery": "^2.2.3",
    "postcss-loader": "^2.1.0",
    "react": "^0.14.8",
    "react-autocomplete": "^1.0.0-rc2",
    "react-dom": "^0.14.7",
    "react-sound": "^0.4.0",
    "semantic-ui-css": "^2.2.14",
    "semantic-ui-react": "^0.78.2",
    "soundmanager2": "^2.97.20150601-a",
    "style-loader": "^0.20.1",
    "url-loader": "^0.6.2",
    "webpack": "^3.11.0"
  }
}
  • for this to workin I have an extra file in my root directory named postcss.config.js which is
  • postcss.config.jss
module.exports = {};

I would like to tell you that I am using React with Semantic-ui-react and this configuration is rocking. You can try. If you face any error tell me.

From spelunking the same code, it appears that options: { babelrc: true } will also trigger the default behavior. I have no idea why that would not be the default, but hey.

I was successfully using @finom’s solution above.

After upgrading to the official Babel 7 release, due to other issues, I eventually had to migrate .babelrc to babel.config.js by following these docs: https://babeljs.io/docs/en/next/configuration.html, which basically explain that anyone who needs to compile anything in node_modules needs to use babel.config.js.

Then I was able to remove that JSON.parse... hack, and everything seems to work great now!

Direct read of .babelrc is helped for me:

options: {
   ...JSON.parse(fs.readFileSync(path.resolve(__dirname, '../.babelrc'))),
 },

I see the real issue now after some more investigation, babel.transform does not read .babelrc file; however, all the other functions do such as babel.transformFile|transformFileSync|.... This loader is executing babel.transform, so you have to pass in the options. I’m not sure if this fix should be in the babel-loader project or the babel-core project.

@al-the-x just to point out that babelrc: true is incorrect. If you take a look here, it’s actually a string type not a boolean type. And the string is supposed to be the relative path to the .babelrc file.

So the issue can be resolved in two ways:

  1. Fix babel-core#transform to read the .babelrc configurations or
  2. When passing in a path for options.babelrc it reads and parses it and passes it as the options to babel.transform. Because nowhere in the code actually reads the .babelrc file and passes it through.

The babelrc path gets assign here, and then gets removed here, and transpile doesn’t get it. Where it needs to get added separately is here.

@skukan159 const fs = require('fs');

None of the above solutions worked for me, but this is:

const _flow = require('lodash/fp/flow');
const _omit = require('lodash/fp/omit');
const config = _flow(require('rc'), _omit(['_', 'config', 'configs']));

    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'babel-loader',
                options: config('babel'),
            },
        ],
    },

So actually, I’m getting the .babelrc file and use it’s contents as the options for babel-loader

Setting babelrc to a string results in the following for me: Module build failed: Error: .babelrc must be a boolean, or undefined

In my case using babelrc: true did what I was expecting; using the project’s .babelrc file. Imo it would be nice if the .babelrc file is used by default if it’s available.

I encountered this issue on a fresh npm install of all packages when one of the folders involved had it’s own package.json. Screen Shot 2022-02-27 at 6 34 08 PM

Can you please test again with 8.0.0-beta.1. It should be fixed now.

https://github.com/babel/babel-loader/releases/tag/v8.0.0-beta.1

@mohsenuss91 Posting the same question in a lot of closed issues won’t get you an answer if you don’t provide more info.

Please, share your current configuration, your files/directories structure, the behavior you are seeing and the behavior you are expecting.

@pietrofxq babel.config.js is loaded from your working directory by default, so it would depend on what the working directory is.

@al-the-x I readed the babel-laoder’s code, if babelrc is not false, it will find the .babelrc file from the executing directory, which not like node. But if the babelrc is string, like: babelrc: path.resolve(__dirname + “/.babelrc”), it works. But there is another thing, env is not founded, because the presets env is also be read from the excuting directory, it makes me crazy! So, I think we should not use the .babelrc file but config the babel options in the webpack.config.js file!

@al-the-x just to point out that babelrc: true is incorrect. If you take a look here, it’s actually a string type not a boolean type. And the string is supposed to be the relative path to the .babelrc file.

That’s not how I read that code, @nguyenj:

  // https://github.com/babel/babel-loader/blob/7.x/src/index.js#L116-L122
  if (loaderOptions.babelrc !== false) {
    babelrcPath =
      typeof loaderOptions.babelrc === "string" &&
      exists(fileSystem, loaderOptions.babelrc)
        ? loaderOptions.babelrc
        : resolveRc(fileSystem, path.dirname(filename));
  }

Refactored for more clarity using some lodash operations not in the original:

if (loaderOptions.babelrc !== false) { // if not explicitly `false`
  if (_.isString(loaderOptions.babelrc)) { // `babelrc` is a string value
    if (exists(fileSystem, loaderOptions.babelrc)) { // `babelrc` refers to an existing file
      babelrcPath = loaderOptions.babelrc; // use the file that `babelrc` refers to
  } else { // `babelrc` is _not_ a filename, so any non-string, non-`false` value, including `true`
      babelrcPath = resolveRc(fileSystem, path.dirname(filename));
      // use `resolveRc` to find the appropriate RC file relative to the `filename` from the `require` request
  }
}

This explains the positive experience (boolean pun!) that @thasmo and I had:

In my case using babelrc: true did what I was expecting; using the project’s .babelrc file.

Nice bit of detective work tracing the babel.transpile call, though. Since we know that babelrc:true would work by default without a change to the upstream babel or using one of the transpileFile|transpileFileSync methods, perhaps we could make babelrc default to true in the options?

The shorthand babel-loader?babelrc works for me, as well and is less to (remember to) type, but I’d still prefer the default.

@nguyenj I think a better approach might be to highlight in the documentation that you have to set babelrc:true on the loader if you have a .babelrc file in the project and to the path of the file if it’s not the default name and location. I’d prefer to see that option default to true, personally, as long as Babel doesn’t blow up if the file is missing.