Search code examples
javascriptjsonwebpackwebpack-loader

Prevent Webpack's default loaders from running


Webpack has a JSON loader built into it. How can I write a custom loader that doesn't try to run the built-in JSON loader on the result?

Basically, I want my loader to take in a config object (stored in a JSON file) and generate source code from that configuration, which is no longer valid JSON, it's JavaScript (which could subsequently be fed through babel-loader).

Here's a really stupid, contrived example. The source file is a JSON file, but I want the output of my loader to instead be some JS.

Loader

function compile(doc) {
  return `alert(${JSON.stringify(doc.title)})`
}

function myLoader(source) {
  return compile(JSON.parse(source))
}

Webpack config

rules: [
  {
    test: /\.json$/,
    use: [
      'babel-loader',
      'my-loader',
    ],
  },
],

Instead, I end up getting this error:

ERROR in ./config.json
Module parse failed: Unexpected token ' in JSON at position 0
You may need an appropriate loader to handle this file type.
SyntaxError: Unexpected token ' in JSON at position 0
  at JSON.parse (<anonymous>)
  at JsonParser.parse (.../node_modules/webpack/lib/JsonParser.js:15:21)

As you can see from the stack trace, it's coming from webpack/lib/JsonParser.js. How can I tell Webpack not to run its built-in JSON parser in the first place, and instead delegate the processing of JSON files that match this rule to my loader?


Solution

  • I think I figured it out, although it appears to be an undocumented feature (at least, I couldn't find it on the configuration docs.

    It looks like one of the properties you can pass in the Rule object is type. By setting it to javascript/auto, you can override the default JSON parser and have it parse the source of the file as JavaScript.

    This property is in the JSON schema used by Webpack to validate the config object.

    rules: [
      {
        test: /\.json$/,
        use: [
          'babel-loader',
          'my-loader',
        ],
        type: 'javascript/auto',
      },
    ],