Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Webpack error when importing a json file

Here is a simple test case that breaks:

First, save a json file from Node:

const fs = require('fs')

let test = {
  foo: [
    { 1: 'a'},
    { 2: 'b'}
  ]
};

fs.writeFileSync('./test.json', JSON.stringify(test), 'utf-8');

Then, try importing this json into a js file that is processed by Webpack (I am using the latest version of Webpack, 3.4.1):

import test from './test.json';

console.log(test);

This fails with the following error:

ERROR in ./test.json                                       
Module build failed: SyntaxError: Unexpected token, expected ; (1:6)

> 1 | {"foo":[{"1":"a"},{"2":"b"}]}

The offending character that the console output is pointing at is the colon after "foo".

My Webpack config was very simple, with only these module options:

  module: {
    rules: [
      {
        test: /\.js/,
        exclude: [ path.resolve(__dirname, 'node_modules') ],
        loader: 'babel-loader'
      },
      {
        test: /\.css$/,
        use: ExtractTextPlugin.extract({
          fallback: "style-loader",
          use: "css-loader"
        })
      }
    ]
  },

Confused, I opened the JSON loader page, which informed me that:

Since webpack >= v2.0.0, importing of JSON files will work by default.

Since I was using Webpack v. 3.4.1, I assumed json-loader was unnecessary. Still, out of desperation, I added the following rule to the modules field of Webpack config:

  {
    test: /\.json/,
    loader: 'json-loader'
  }

This actually worked! The json file got loaded, and the error disappeared.

So my question is: was I doing something wrong with Webpack trying to import the json file, or is the newest Webpack somehow broken as regards to the importing of json files?

like image 344
azangru Avatar asked Mar 08 '23 10:03

azangru


1 Answers

The regular expression you used for the .js rule also matches .json, because all you're looking for is a .js anywhere in the path. All of the following would match successfully (most of them aren't likely to be imported or even exist):

file.js
file.json
file.js.backup
.js/file.css
.jshintrc

test.json matches the regular expression, which means that you are applying babel-loader to it. Babel only accepts JavaScript and JSON will fail to parse. The reason that it complains about the colon (:) is because with ES6 you can create a new scope with curly brackets. For example:

const msg = "Outer";

// Entering new scope
{
  // msg is free in this scope, shadows the outer one.
  const msg = "Inner";
  console.log(msg); // Inner
}
// Exiting scope

console.log(msg); // Outer

// SyntaxError: Identifier 'msg' has already been declared
const msg = "Re-definition";

I don't think there are many uses of this in JavaScript, but it is used a lot more in other languages (e.g. Rust). The opening curly bracket of the JSON started a new scope, not an object, and a colon is not valid after a string in JavaScript.

To not apply babel-loader to .json files you need to only match .js at the end of the path, by using the $ anchor (end of string), like you did with the .css rule.

{
  test: /\.js$/,
  exclude: [ path.resolve(__dirname, 'node_modules') ],
  loader: 'babel-loader'
},
like image 117
Michael Jungo Avatar answered Mar 11 '23 04:03

Michael Jungo