webpack-contrib / file-loader

File Loader
MIT License
1.86k stars 257 forks source link

file-loader fails with JSON files in Webpack 4 #259

Closed enjikaka closed 6 years ago

enjikaka commented 6 years ago

Using import 'file-loader!./manifest.json'; fails with;

Module parse failed: Unexpected token m in JSON at position 0
You may need an appropriate loader to handle this file type.
SyntaxError: Unexpected token m in JSON at position 0
    at JSON.parse (<anonymous>)
    at JsonParser.parse (/Users/jeremy/Documents/Development/webpack-file-loader-test/node_modules/webpack/lib/JsonParser.js:15:21)
    at doBuild.err (/Users/jeremy/Documents/Development/webpack-file-loader-test/node_modules/webpack/lib/NormalModule.js:367:32)
    at runLoaders (/Users/jeremy/Documents/Development/webpack-file-loader-test/node_modules/webpack/lib/NormalModule.js:264:12)
    at /Users/jeremy/Documents/Development/webpack-file-loader-test/node_modules/loader-runner/lib/LoaderRunner.js:370:3
    at iterateNormalLoaders (/Users/jeremy/Documents/Development/webpack-file-loader-test/node_modules/loader-runner/lib/LoaderRunner.js:211:10)
    at iterateNormalLoaders (/Users/jeremy/Documents/Development/webpack-file-loader-test/node_modules/loader-runner/lib/LoaderRunner.js:218:10)
    at /Users/jeremy/Documents/Development/webpack-file-loader-test/node_modules/loader-runner/lib/LoaderRunner.js:233:3
    at runSyncOrAsync (/Users/jeremy/Documents/Development/webpack-file-loader-test/node_modules/loader-runner/lib/LoaderRunner.js:130:11)
    at iterateNormalLoaders (/Users/jeremy/Documents/Development/webpack-file-loader-test/node_modules/loader-runner/lib/LoaderRunner.js:229:2)
    at Array.<anonymous> (/Users/jeremy/Documents/Development/webpack-file-loader-test/node_modules/loader-runner/lib/LoaderRunner.js:202:4)
    at Storage.finished (/Users/jeremy/Documents/Development/webpack-file-loader-test/node_modules/webpack/node_modules/enhanced-resolve/lib/CachedInputFileSystem.js:43:16)
    at provider (/Users/jeremy/Documents/Development/webpack-file-loader-test/node_modules/webpack/node_modules/enhanced-resolve/lib/CachedInputFileSystem.js:79:9)
    at /Users/jeremy/Documents/Development/webpack-file-loader-test/node_modules/graceful-fs/graceful-fs.js:78:16
    at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:505:3)

Minimal reproducible setup: https://ipfs.io/ipfs/QmPfPq71WD3H6RrcCu1y72FswF8zC3f43aU8FPv5ZwS2ea

enjikaka commented 6 years ago

I assume this is related to webpack 4 now handling JSON loading natively

alexander-akait commented 6 years ago

@enjikaka seems bug in webpack@4, he should ignore .json files which loaded other loaders

alexander-akait commented 6 years ago

@webpack-bot move to webpack/webpack

michael-ciniawsky commented 6 years ago

@see https://github.com/webpack/webpack/issues/6586. Why is the file-loader even needed here ? Either explicitly add the type to the rule in webpack.config.js or use a different extname for inline usage (e.g x.manifest). The inline loader syntax is discouraged for a while now and it would even work in case x-loader supports module.type = 'json'.

joelcollyer commented 6 years ago

For anyone who's encountering the error Module parse failed: Unexpected token m in JSON at position 0 like I was, and you find this thread, you don't need to specify that json files be loaded in any special way.

Simply require your files like this:

const langFile = require('./locale/en/lang.json');

Webpack 4.x will do the rest.

No special tests, configuration, or loaders are needed for .json to be required in your JavaScript.

rlefever68 commented 6 years ago

Please check the encoding of your .json file. It is probably 'UTF-8 with BOM'. Resave the file with pure 'UTF-8' and it should be solved.

jminnick commented 6 years ago

@joelcollyer not sure why the down votes on your post as removing the loader in my Webpack config worked for me.

I guess the only reason I can think of is it assumes you are using Webpack 4[x].

Again, if you are using Webpack 4[x] @joelcollyer is correct.

BobbyBabes commented 6 years ago

@joelcollyer The only problem with using require() to read JSON files, is that the file will be cached. Unless it's deleted from require()'s cache.

joelcollyer commented 6 years ago

@BobbyBabes: I fully agree; it'd be best to fetch json with an async request most of the time.

In this case we were loading a mandatory language file, so the require isn't so bad. If you try to do that with an import tree shaking gets in the way and the file isn't loaded.

My point was mostly that no webpack configuration is required for it to understand the loading of a json file (unlike the additional configuration you'd have to do for say, sass, or jsx loading).

crloshro commented 5 years ago

@joelcollyer thank you so much, that tip helped me to fix the bug!

naretini commented 5 years ago

In my package.json I have: "scripts":{ ... "build-mydir01": "webpack --env.ext mydir01 --mode production ./code/mydir01/index.js --output ./public/mydir01/main.js", ... }

In my webpack.config.js: ` const HtmlWebPackPlugin = require("html-webpack-plugin");

module.exports = function (env) { console.log(env, env); const ext = env.ext || 'src';

const ext_file = require('./code/' + ext + '/extension.json');

return {
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                exclude: /node_modules/,
                use: {
                    loader: "babel-loader"
                }
            },
            {
                test: /\.(json)$/,
                use: [
                    {
                        loader: 'file-loader',
                        options: {},
                    },
                ],
            },
            {
                test: /\.(html)$/,
                use: [
                    {
                        loader: "html-loader"
                    }
                ]
            }
        ]
    },
    plugins: [
        new HtmlWebPackPlugin({
            template: `./code/${ext}/index.html`,
            filename: "./index.html"
        })
    ]
}

}; `

After executing:

npm run build-mydir01

In my ./public/mydir01/ i see index.html and main.js but extension.json is not moved there.... What do I miss?

blachawk commented 5 years ago

Is there any official documentation on how to output JSON files to my /dist folder with Webpack 4?

Simply adding const langFile = require('./locale/en/lang.json'); to my webpack.config.js file does not tell me much or do much for me with Webpack 4. I still encounter the same error.

garkin commented 4 years ago

Correct way to use file-loader with JSON in Webpack 4+:

{
    test: /\.json$/,
    loader: 'file-loader',
    type: 'javascript/auto'
},
zaitebaki commented 4 years ago

Correct way to use file-loader with JSON in Webpack 4+:

{
  test: /\.json$/,
  loader: 'file-loader',
  type: 'javascript/auto'
},

best wishes, you awesome :))) With saving path:

      {
        test: /\.json$/,
        loader: 'file-loader',
        type: 'javascript/auto',
        options: {
          name() {
            return '[path][name].[ext]';
          },
        },
      }
Garwin4j commented 4 years ago

Correct way to use file-loader with JSON in Webpack 4+:

{
    test: /\.json$/,
    loader: 'file-loader',
    type: 'javascript/auto'
},

best wishes, you awesome :))) With saving path:

      {
        test: /\.json$/,
        loader: 'file-loader',
        type: 'javascript/auto',
        options: {
          name() {
            return '[path][name].[ext]';
          },
        },
      }

So I do this, the project build and loads, but it seem the JSON import is undefined like it isn't ready the JSON. is anyone else getting this? Does your application still recognize the JSON values after doing tihs.

kevinlabx commented 4 years ago

Correct way to use file-loader with JSON in Webpack 4+:

{
  test: /\.json$/,
  loader: 'file-loader',
  type: 'javascript/auto'
},

@garkin Thank you this actually works.

stories2 commented 4 years ago

Correct way to use file-loader with JSON in Webpack 4+:

{
    test: /\.json$/,
    loader: 'file-loader',
    type: 'javascript/auto'
},

best wishes, you awesome :))) With saving path:

      {
        test: /\.json$/,
        loader: 'file-loader',
        type: 'javascript/auto',
        options: {
          name() {
            return '[path][name].[ext]';
          },
        },
      }

With exclude node_modules it makes best for me.

{
        test: /\.json$/,
        loader: 'file-loader',
        type: 'javascript/auto',
        exclude: /node_modules/
      }
RezaZR commented 4 years ago

Adding esModule works best for me. Thank you for the solution


{
        test: /\.json$/,
        use: [
          {
            loader: "file-loader",
            options: {
              esModule: false,
            },
          },
        ],
        type: "javascript/auto",
      },
Richifg commented 4 years ago

Correct way to use file-loader with JSON in Webpack 4+:

{
  test: /\.json$/,
  loader: 'file-loader',
  type: 'javascript/auto'
},

This is working for me, my bundle now builds successfully and I have a separate JSON file, but now my app stop working. The js in the bundle that imports the JSON file is only getting a string with the file name instead of the javascript object I was receiving before extracting the JSON file from the bundle.

Any idea what can he causing this?

Garwin4j commented 4 years ago

I had the same problem. For this you have to read the file as a normal text file and transform it at runtime:

 return Axios.get(`/Config.json`, {
        method: 'GET',
      }).then(x => {
        ConfigService.globalConfig = x.data;
        return ConfigService.globalConfig;
      });

The thing to consider thou is to ensure this is done before the file is used in code.

Note that I spit out the file at the root of the app:

{
    test: /\Config.json$/,
    loader: 'file-loader',
    type: 'javascript/auto',
    options: {
      name(file) {
        return '[name].[ext]';
      },
    },
  }
Richifg commented 4 years ago

@Garwin4j thanks for the quick reply, yes I ended loading the failed asyncronously as well. I did it with fetch api and it worked well.

fetch('content.json')
      .then((res) => res.json())
      .then((data) => console.log(data))

In this example the file is also at the root.

Eli-Black-Work commented 4 years ago

So, to sum this up:

If you want Webpack to load the contents of your JSON, so that you can immediately use it in your code, don't use file-loader at all. (https://github.com/webpack-contrib/file-loader/issues/259#issuecomment-391779346)

Example:

Your code

import languages from './languages.json';

console.log(translations);  // { english: 'English', spanish: 'Español' }

This method has a downside: The entire contents of the JSON file gets bundled into your app's .js file, which of course makes your app larger.

If you want to load your JSON file via AJAX, use file-loader. (https://github.com/webpack-contrib/file-loader/issues/259#issuecomment-541492227)

Example:

Webpack config file

{
    test: /\.json$/,
    loader: 'file-loader',
    type: 'javascript/auto'
}

Your code

import languagesFileUrl from './languages.json';

console.log(languagesFileUrl);  // This just returns the URL of your JSON file. For example: '/languages.json'. You should then fetch the file via AJAX.

fetch(languagesFileUrl)
...