93

I'm using webpack + babel. I have three modules looking like this:

// A.js

// some other imports here
console.log('A');
export default 'some-const';

// B.js

import someConst from './A';
console.log('B', someConst);
export default 'something-else';

// main.js

import someConst from './A';
import somethingElse from './B';
console.log('main', someConst);

When main.js is executed, I see the following:

B undefined
A
main some-const

If I swap the imports in main.js, B becoming the first, I get:

A
B some-const
main some-const

How come B.js gets undefined instead of a module in the first version? What's wrong?

loganfsmyth
  • 156,129
  • 30
  • 331
  • 251
Alec Mev
  • 4,663
  • 4
  • 30
  • 44

3 Answers3

212

After almost a full workday of narrowing down the issue (AKA hair-pulling), I've finally came to realize that I have a circular dependency.

Where it says // some other imports here, A imports another module C, which, in turn, imports B. A gets imported first in main.js, so B ends up being the last link in the "circle", and Webpack (or any CommonJS-like environment, for that matter, like Node) just short-circuits it by returning A's module.exports, which is still undefined. Eventually, it becomes equal to some-const, but the synchronous code in B ends up dealing with undefined instead.

Eliminating the circular dependency, by moving out the code that C depends on out of B, has resolved the issue. Wish Webpack would somehow warn me about this.

Edit: On the last note, as pointed out by @cookie, there's a plugin for circular dependency detection, if you'd like to avoid hitting this problem [again].

Alec Mev
  • 4,663
  • 4
  • 30
  • 44
  • 25
    there is a plugin for webpack that'll detect circular dependencies: https://www.npmjs.com/package/circular-dependency-plugin – cookie Sep 08 '16 at 13:32
  • 6
    You are a freaking hero. Webpack is such a dumpster fire---this just blew up my vue.js site. It turns out that if component X imports vuex state Y + js module Z, and Y and Z both import the same JSON FILE, somehow that constitutes a circular dependency. Would have never fixed it but for this SO. – Paul Gowder Feb 09 '18 at 18:40
  • 3
    So... if webpack emits broken code because it doesn't support circular dependencies (I'm not arguing it should support bad design), then how come we need a plugin that tells us that we have a problem? – joonas.fi Feb 13 '19 at 10:50
  • 2
    @joonas.fi: I agree. IMO with the JS ecosystem it usually comes down to https://www.jwz.org/doc/worse-is-better.html – johncip Mar 04 '19 at 04:55
1

This plugin(pointed above) solved the issue for me as well.

I recommend setting this flag to avoid adding additional circular dependencies in the future.

// add errors to webpack instead of warnings
failOnError: true

There is also a eslint plugin to address it.

Raz
  • 434
  • 7
  • 6
1

In my case problem was solved by changing output libraryTarget to commonjs2 in the webpack config:

  output: {
    path: `${__dirname}/dist`,
    filename: '[name].js',
    libraryTarget: 'commonjs2',
  },
mseyfayi
  • 116
  • 5