0

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?

Community
  • 1
  • 1
Matt
  • 23,363
  • 39
  • 111
  • 152
  • Did you just try: `test: path.join(__dirname, 'src/globals.js')` ? – Sergeon Mar 11 '19 at 14:57
  • That allows me to build and run, but `file` is undefined in my `./src/index.js` console.log statement. So I'm still not sure it's configured properly... – Matt Mar 11 '19 at 15:01
  • As far as I know, `test` basically expects a regex expression, so any string with a valid file path should be ok, so you don't explicitly need `require.resolve` for `test` to work. Now, apart from that, I don't know why your project is not bundling as expected. Good luck! – Sergeon Mar 11 '19 at 15:03
  • Thanks. New question posted to follow up on the remaining part of this question. – Matt Mar 11 '19 at 15:17
  • There is something I don't find clear in your question: you're just trying to get `webpack-exports-loader` to work in your regular .js files? Or is it something more? – Sergeon Mar 11 '19 at 15:22

1 Answers1

0

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);
Sergeon
  • 6,638
  • 2
  • 23
  • 43
  • Sergeon, see Webpack's own example of `exports-loader` that *does* use the webpack config file: https://webpack.js.org/guides/shimming/#global-exports. However, I was unable to get this to work, and asked that question here: https://stackoverflow.com/questions/55106256/why-does-the-exports-loader-example-in-webpacks-documentation-not-work# – Matt Mar 11 '19 at 18:44
  • To expand on my previous comment, there appear to be 2 distinct ways to use `exports-loader`: (1) via webpack config file (webpack.config.js), and (2) "inline", via the `import` method you described. I was indeed able to get this to work by removing *all* `exports-loader` config from my `webpack.config.js`, and using *only* `import file from 'exports-loader?file!./globals.js`. So to sum up, using the plugin inline appears to work while using the file configuration approach does not. – Matt Mar 11 '19 at 18:51
  • In their github page, there is not any documentation about the global configuration way. Maybe you can get it to work if you open an issue there, so: 1) they improve their docs 2) they suggest you how to do this. I will explore if I can get the global config way to work – Sergeon Mar 12 '19 at 08:27