Using require.resolve in webpack config yields runtime error: "The provided value"..."is not an absolute path!"

963 Views Asked by At

I am attempting to use the exports-loader with my webpack config, but I'm running into an issue when trying to configure it.

webpack.config.js

module.exports = {
    module: {
        rules: [
            {
                test: require.resolve('./src/globals.js'),
                use: 'exports-loader?file,parse=helpers.parse'
            }
        ]
    }
};

./src/globals.js

var file = 'blah.txt'
var helpers = {
    test: function() { console.log('test something'); },
    parse: function() { console.log('parse something'); }
}

./src/index.js

import { file } from './globals.js'
console.log('the file', file);

My application builds fine, but when I attempt to run it I get:

WebpackOptionsValidationError: Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.

  • configuration.module.rules[0].test should be one of these:
    • configuration.module.rules[0].test: The provided value "./src/globals.js" is not an absolute path!

To be completely clear, I understand the difference between an absolute and a relative path, and I know that the value I'm using is a relative path. My confusion is two-fold:

  1. require.resolve allows relative paths, so why can I not use it here?
  2. If I cannot use a relative path, how can I refer to that file otherwise?

I tried using an absolute path for the test property like so:

test: require.resolve(path.join(__dirname, 'src/globals.js'))

But I get this error when I attempt to run:

Error: Cannot find module '/workspace/my-app/dist/src/globals.js

So I'm stuck. How can I properly configure this loader to reference that file appropriately?

1

There are 1 best solutions below

3
Sergeon On

Getting exports-loader to work

Exports loader is a webpack loader that allows to dynamically add exports sentences to javascript files loaded with it. For instance, your globals.js file does not have any export in it, only the file and helpers variables, yet with exports-loader it can work as if it had export clauses.

Loading webpack loaders

Basically, to use a loader we must to provide a test and an use clauses. The test can be a regex, an array or an object, and basically it decides which files will use certain loaders.

The use clause decides which loaders will be applied to the files that match the test regex.

In this case, we should -for instance- instruct webpack to load globals.js with exports-loader:

  module: {
    rules: [
      {
        test: /globals.js/,
        use: 'exports-loader',
      }
    ]
  }

This is -afaik- the most common way to use loaders. Webpack, however, has a lot of configuration options and different valid syntaxes.

Once we do this, when webpack finds a require or an import agains a globals.js file, it will use the exports-loader.

On other hand, exports-loader works by modifying the require calls to instruct it how to extract variables in the required file. As in their docs:

file.js

const file = 'foo';

app.js

const file = require('exports-loader?file!./file.js');
console.log(file); // foo

So, basically you need two things to get exports-loader to work:

  1. Use require or import with their special syntax.

  2. Load the loader in the webpack.config.js as usual (they skip this in their documentation).

Instead, you're trying to use this specific exports-loader syntax in your webpack.config.js file, and then using it with import.

So, bad news are that exports-loader need some special formatting in every require or import statement to do its magic. You just cannot specify this in your config file as you are trying (or, at least, I don't know how to).

So, to get it to work, you need to:

  • Fix your webpack.config.js as stated above.
  • change your index.js file so it uses the exports-loader magic:
import file from 'exports-loader?file!./deps.js'
console.log('the file', file);