How to solve this basic ES6-module circular dependency problem?
/#!/JoePea
joe at trusktr.io
Thu Aug 11 07:23:02 UTC 2016
Alright, so I believe I have found the solution. It is not possible to
guarantee a certain module evaluation order, but using some clever (but
tedious) conditional checking I believe the problem is solved (with two
caveats listed after):
```js
// --- Entrypoint
import A from './A'
console.log('Entrypoint', new A)
```
```js
// --- Module A
import C from './C'
import {setUpB} from './B'
let A
export
function setUpA(C) {
if (!A) {
A = class A extends C {
// ...
}
}
}
if (setUpA && C) setUpA(C)
if (setUpB && C) setUpB(C)
export {A as default}
```
```js
// --- Module B
import C from './C'
import {setUpA} from './A'
let B
export
function setUpB(C) {
if (!B) {
B = class B extends C {
// ...
}
}
}
if (setUpA && C) setUpA(C)
if (setUpB && C) setUpB(C)
export {B as default}
```
```js
// --- Module C
import A, {setUpA} from './A'
import B, {setUpB} from './B'
class C {
constructor() {
// this may run later, after all three modules are evaluated, or
// possibly never.
console.log(A)
console.log(B)
}
}
if (setUpA && C) setUpA(C)
if (setUpB && C) setUpB(C)
export {C as default}
```
The caveat is that this fails in both Babel environments and in Rollup. For
it to work in Babel environments, `let A` and `let B` have to be changed to
`let A = A` and `let B = B`, as per the [fault in Babel's
ES2015-to-CommonJS implementation](
https://github.com/meteor/meteor/issues/7621#issuecomment-238992688)
pointed out by Ben Newman. And it fails in Rollup because Rollup [isn't
really creating live bindings](https://github.com/rollup/rollup/issues/845),
which is fine in most cases, but doesn't work with these circular
dependencies. The Rollup output does not create the C reference before it
is ever used in the first pair of conditional checks, unlike what (I think)
would happen with real live bindings (please correct me if wrong). To
understand what I mean in the case of Rollup, just run `if (FOO)
console.log(FOO)` in your console, and you'll get an error because FOO is
not defined. Had the bindings been live, then FOO *would* be defined.
*/#!/*JoePea
On Wed, Aug 10, 2016 at 5:04 PM, /#!/JoePea <joe at trusktr.io> wrote:
> I found a solution that works in environments compiled by Babel, using the
> [workaround suggested by Ben Newman](https://github.com/met
> eor/meteor/issues/7621#issuecomment-238992688):
>
> ```js
> // --- Module A
>
> import C from './C'
>
> let A = A // @benjamn's workaround applied
>
> export
> function setUpA(C) {
>
> A = class A extends C {
> // ...
> }
>
> }
>
> export {A as default}
> ```
>
> ```js
> // --- Module B
>
> import C from './C'
>
> let B = B // @benjamn's workaround applied
>
> export
> function setUpB(C) {
>
> B = class B extends C {
> // ...
> }
>
> }
>
> 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)
> setUpB(C)
>
> export {C as default}
> ```
>
> ```js
> // --- Entrypoint
>
> import A from './A'
> console.log('Entrypoint', new A) // runs the console.logs in the C
> constructor.
> ```
>
>
> Although that works in my environment which is compiled from ES6 modules
> to CommonJS by Babel, it [doesn't work in Rollup.js](http://goo.gl/PXXBKI),
> and may not work in other ES6 module implementations.
>
> Is there some solution that will theoretically work in any ES6 module
> environment?
>
> */#!/*JoePea
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20160811/5efae6e6/attachment.html>
More information about the es-discuss
mailing list