Modifying ES6 module exports

/#!/JoePea joe at trusktr.io
Tue Dec 22 03:25:41 UTC 2015


I'm curious, what should happen when module A imports the default from
module B which imports the default from module A? Should the exported
A object exist inside of module B?

Here's two modules A and B (simplified from some real code that I
have), which have a circular dependency:

```js
// A.js
import B from './B'
let A = window.globalThing
export default A

// modify the A object adding methods that reference B.
```

```js
// B.js
import A from './A'
let B = new window.OtherThing
export default B

console.log(A) // an empty object, {}

// modify the B object which depends on A existing (not being some temporary
// object like I get with Webpack) while the module is evaluated.
```

When using Webpack, this code fails because the reference to A in B is
some empty object. If I import both A and B into main.js, then A is
defined as epected:

```js
// main.js
import A from './A'
import B from './B'

console.log(A) // An object with a bunch of properties, as expected.
```

I can fix my problem by exporting functions to do setup of A and B,
and running those functions in main.js, like this:

```js
// A.js
import B from './B'
let A = window.globalThing
export default A

A.setup = () => {
  // modify the A object adding methods that reference B.
}
```

```js
// B.js
import A from './A'
let B = new window.OtherThing
export default B

console.log(A) // an empty object, {}

B.setup = () => {
  console.log(A) // the expected object!! Why?

  // modify the B object which depends on A existing (not being some temporary
  // object like I get with Webpack) while the module is evaluated.
}
```

When using Webpack, this code fails because the reference to A in B is
just `{}`, some empty object. If I import both A and B into main.js,
then A is defined as epected:

```js
// main.js
import A from './A'
import B from './B'

A.setup()
B.setup()

// no more problems!

console.log(A) // An object with a bunch of properties, as expected.
```

So, if I run the setup for A and B in main.js instead of in the module
evaluation, everything works perfectly.

This led me to wonder: What is the expected behavior of circular
dependencies in ES2015? Have you had this 'empty object' problem
before? Is that expected to happen, or might there be a bug in
Webpack?

I guess the problem makes sense: How can the first method (running
relying on module evaluation for setting up A and B exports) work if
module B depends on the evaluation of module A which depends on the
evaluation of module B?


More information about the es-discuss mailing list