How to solve this basic ES6-module circular dependency problem?

/#!/JoePea joe at trusktr.io
Wed Aug 10 06:12:18 UTC 2016


I can get the whole thing to work if I pass the C dependency into the
`setUpA` and `setUpB` functions as follows, but oddly `A` is `undefined` in
the Entrypoint module at the `console.log` statement, which makes it seem
to me like live bindings aren't working the I was expecting.

```js
// --- Entrypoint

import A from './app/A'
console.log('Entrypoint', A) // HERE, output: "Entrypoint undefined"
```

```js
// --- Module A

import C from './C'

let A

export
function setUpA(C) {

    console.log('setUpA')
    console.log(C)

    A = class A extends C {
        // ...
    }

}

console.log('Module A', C, setUpA)

export {A as default}
```

```js
// --- Module B

import C from './C'

let B

export
function setUpB(C) {

    console.log('setUpB', C)

    B = class B extends C {
        // ...
    }

}

console.log('Module B', C, setUpB)

export {B as default}
```

```js
// --- Module C

import A, {setUpA} from './A'
import B, {setUpB} from './B'

let C = class C {
    constructor() {
        // this may run later, after all three modules are evaluated, or
        // possibly never.
        console.log(A)
        console.log(B)
    }
}

setUpA(C)
console.log('Module C', A)

setUpB(C)
console.log('Module C', B)

export {C as default}
```

*/#!/*JoePea

On Tue, Aug 9, 2016 at 9:59 PM, /#!/JoePea <joe at trusktr.io> wrote:

> It seems that the environment I'm in (Meteor uses [reify](
> https://github.com/benjamn/reify)) tries to evaluate A and B first, so I
> thought I could take advantage of "live bindings" by changing my modules to
> the following:
>
> ```js
> // --- Entrypoint
>
> import A from './app/A'
> console.log('Entrypoint', A)
> ```
>
> ```js
> // --- Module A
>
> import C from './C'
>
> let A
>
> export
> function setUpA() {
>
>     console.log('setUpA')
>     console.log(C)
>
>     A = class A extends C {
>         // ...
>     }
>
> }
>
> console.log('Module A', C, setUpA)
>
> export {A as default}
> ```
>
> ```js
> // --- Module B
>
> import C from './C'
>
> let B
>
> export
> function setUpB() {
>
>     console.log('setUpB', C)
>
>     B = class B extends C {
>         // ...
>     }
>
> }
>
> console.log('Module B', C, setUpB)
>
> export {B as default}
> ```
>
> ```js
> // --- Module C
>
> import A, {setUpA} from './A'
> import B, {setUpB} from './B'
>
> let C = class C {
>     constructor() {
>         // this may run later, after all three modules are evaluated, or
>         // possibly never.
>         console.log(A)
>         console.log(B)
>     }
> }
>
> setUpA()
> console.log('Module C', A)
>
> setUpB()
> console.log('Module C', B)
>
> export {C as default}
> ```
>
> As you can see, modules A and B simply export the code that should be
> evaluated (note the live bindings). Then finally, the C module is evaluated
> last. At the end of the C module, you see that it calls `setUpA` and
> `setUpB`. When it fires `setUpA`, an error is thrown on the second
> `console.log` that `C` is undefined (or, specifically, `C.default` is
> `undefined` because the ES6 modules are compiled into CommonJS form).
>
> I thought that if `C` was a live binding, then it should be ready by the
> time the `setUpA` function is called. Should this in fact be the case?
>
> */#!/*JoePea
>
> On Tue, Aug 9, 2016 at 5:36 PM, John Lenz <concavelenz at gmail.com> wrote:
>
>> Without a way to load "later" (aka "soft") dependencies, ES6 module will
>> continue to be more or less broken for circular dependencies.
>>
>> On Tue, Aug 9, 2016 at 4:11 PM, Tab Atkins Jr. <jackalmage at gmail.com>
>> wrote:
>>
>>> On Tue, Aug 9, 2016 at 4:00 PM, /#!/JoePea <joe at trusktr.io> wrote:
>>> > True, and so that's why I'm wondering if the module system can see
>>> that it
>>> > can satisfy all module requirements if it simply evaluates module C
>>> first,
>>> > followed by A or B in any order. It is easy for us humans to see that.
>>> It
>>> > would be nice for the module system to see that as well (I'm not sure
>>> if
>>> > that is spec'd or not).
>>>
>>> That knowledge requires, at minimum, evaluating the rest of each
>>> module, beyond what is expressed in the `import` statements.  That's
>>> assuming there's no dynamic trickery going on that would invalidate
>>> whatever assumptions it can draw from surface-level analysis.
>>>
>>> Because of this, only the `import` statements are declaratively
>>> available to the module system to work with.  Based on that, it
>>> definitely can't make any ordering assumptions; all it knows is that A
>>> imports C, B imports C, and C imports both A and B, making a circular
>>> import.
>>>
>>> ~TJ
>>> _______________________________________________
>>> es-discuss mailing list
>>> es-discuss at mozilla.org
>>> https://mail.mozilla.org/listinfo/es-discuss
>>>
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20160809/3b149e5a/attachment-0001.html>


More information about the es-discuss mailing list