Reputation: 2748
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?
Upvotes: 4
Views: 4741
Reputation: 33002
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'
},
Upvotes: 9