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

/#!/JoePea joe at trusktr.io
Sun Oct 9 02:46:19 UTC 2016


Yep, I believe that the first error was solved by moving the import
statement to the top!

As for the second error, I think (but not yet sure) that the problem might
be due to the circular dependency `src/motor-html/node ->
src/motor/Transformable -> src/motor/Sizeable -> src/motor/Scene ->
src/motor/ImperativeBase -> src/motor/Node -> src/motor-html/node`.

The problem will be solved after I re-organize some things, but if you have
any suggestions it would be greatly appreciated!

I'm still not sure why it works in Reify and not in Webpack.

- Joe


*/#!/*JoePea

On Sat, Oct 8, 2016 at 5:23 PM, /#!/JoePea <joe at trusktr.io> wrote:

> Hello Logan, I wonder if I can borrow your expertise for just a moment:
>
> I ran into another problem. Suppose I have the following code which is
> very similar to the code I had before (using the `var` trick along with
> `initC` function), but now Module C imports `someFunction` from a newly
> added module.
>
> The problem is that module B will be evaluated before both Module C and
> the utilities module. When `initC` is called inside of the B module, the
> `initC` function will try and call `someFunction` but there will be an
> error because the utilities module was not yet evaluated, so `someFunction`
> is undefined.
>
> What would you recommend as a solution?
>
> Here's the code:
>
> ```js
> // --- Entrypoint
> import A from './A'
> console.log('Entrypoint', new A)
> ```
>
> ```js
> // --- Module A
>
> import C, {initC} from './C'
>
> console.log('module A')
> initC()
>
> class A extends C {
>     // ...
> }
>
> export {A as default}
> ```
>
> ```js
> // --- Module B
>
> import C, {initC} from './C'
>
> console.log('module B')
> initC()
>
> class B extends C {
>     // ...
> }
>
> export {B as default}
> ```
>
> ```js
> // --- Module C
>
> import A from './A'
> import B from './B'
> import {someFunction} from './utilities'
>
> console.log('module C')
>
> var C
>
> initC()
>
> export function initC(){
>     if (C) return
>
>     console.log('initC!!!')
>     someFunction()
>
>     C = class C {
>         constructor() {
>             // this may run later, after all three modules are evaluated,
> or
>             // possibly never.
>             console.log(A)
>             console.log(B)
>         }
>     }
> }
>
> export {C as default}
> ```
>
> ```js
> // utilities.js
>
> var someFunction = () => {...}
>
> export {
>     someFunction,
> }
> ```
>
> I think a possible (though strange) solution is to change the import order
> in Module C, f.e.:
>
> ```js
> import A from './A'
> import B from './B'
> import {someFunction} from './utilities'
> ```
>
> I haven't actually tested that example code, but I believe I'm having a
> problem like this with Webpack+Babel here: https://github.com/trusktr/
> infamous/tree/circular-dep-bug
>
> In this case, there is a circular dependency between `src/motor/Scene` and
> `src/motor/Sizeable` (which I've already planned to eliminate, but am still
> curious about how I would solve it without eliminating the circular dep).
> The modules import the defaults of each other, and I'm using the `var
> Sizeable/initSizeable` trick. However, there's a third module, `Utility.js`
> from which the `Sizeable` module needs to import something to use inside of
> the `initSizeable` function.
>
> You can experience the error by simply opening `motor-scratch.html` in
> your browser, in which case you'll get an error like
>
> ```
> Sizeable.js:328: Uncaught TypeError: Cannot read property '
> makeLowercaseSetterAliases' of undefined
> ```
>
> where `makeLowercaseSetterAliases` is akin to the `someFunction` of my
> earlier example. The odd thing is that everything works fine in Meteor's
> Reify environment, and I'm only getting this error when using the bundle
> made by Webpack+Babel.
>
> If I re-order the dependencies in `src/motor/Sizeable` so that they look
> like this:
>
> ```js
> import { makeLowercaseSetterAliases } from './Utility'
> import XYZValues from './XYZValues'
> import Motor from './Motor'
> import Scene from './Scene'
> ```
>
> then the error goes away, but I get another error:
>
> ```
> node.js:129: Uncaught TypeError: Cannot read property 'prototype' of
> undefined
> ```
>
> I have a feeling that moving the import to the beginning solved the
> problem, and that now I have another problem...
>
> If you'd like to test changes (f.e. moving the import statement), you can
> simply:
>
> ```
> npm install
> npm run watch
> ```
>
> which will automatically compile the global.js file after making changes
> to anything in `src`, and you can reload the page in your browser.
>
> Any and all input you may have on this would be greatly appreciated!
>
> Thanks a ton!
>
> All the best,
> - Joe
>
>
> */#!/*JoePea
>
> On Tue, Aug 23, 2016 at 8:55 PM, Logan Smyth <loganfsmyth at gmail.com>
> wrote:
>
>> > Should I open an issue there? And I think you're right about it should
>> throw, because it is strange that the function can be executed before the
>> module is ever evaluated (that seems like it should be impossible), and
>> therefore a TDZ error would happen because the `let` line wasn't
>> theoretically evaluated yet.
>>
>> If you'd like, go for it. To note, Babel 6 doesn't implement TDZ at all
>> at the moment anyway.
>>
>> >  I don't see how it is possible with `var`. How is it that `var`s or
>> `function`s can be hoisted *out of* the module? Is that part of spec? If
>> so, then that is different hoisting from function-based hoisting of pre-ES6.
>>
>> They are not hoisted out of the module. It seems like you may be
>> misunderstanding how modules are linked together.
>>
>> > Pre-ES6 "hoisting" in javascript happens on boundaries set by
>> `function`s, and I thought that modules would be similar to function
>> bodies, and therefore I thought that hoisting would be limited to within a
>> module and did not expect hoisting to go beyond the module boundary to some
>> scope that encompasses multiple modules. That to me is a different type of
>> "hoisting" than what I know from pre-ES6 JavaScript's function-scope
>> hoisting so it isn't necessarily the "same way it'd work with other cases
>> of hoisting"; there is definitely some ES6-module-specific stuff happening
>> that is a little different from pre-ES6 function-scope hoisting. (sidenote:
>> I've asked the awesome Axel of 2ality to add these useful details to his
>> articles.)
>>
>> Hoisting of var and functions behaves the same way in ES6 and in ES5 and
>> you are correct there is no "beyond the module boundary". Let's clarify
>> hoisting in a function.
>>
>> ```
>> function fn() {
>>     console.log(inner());
>>
>>     function inner(){ return "hello world"; }
>> }
>> fn();
>> ```
>> in this context, when an engine executes `fn()`, before any execution has
>> happened inside the `fn`, the engine does the following
>>
>> 1. Create the conceptual function "scope", which exists immediately as
>> soon as the function is called.
>> 2. Look for all function declarations inside `fn` and create their
>> variables and assign their values to point to function objects. This is
>> "function hoisting".
>> 3. Look for all var declarations inside `fn` and create variables with
>> the value `undefined`. This is "var hoisting".
>> 4. Look for all let/const declarations, and create uninitialized
>> variables (these will throw when accessed)
>> 5. A bunch of other stuff I'm skipping
>> 6. Execute the function body itself.
>>
>> A very similar process happens for modules. You can think of it like
>> steps 1-4 running, then before executing the module body (step 6), we
>> recursively do this same process on every imported module. So by the time
>> any module gets to step 6, every imported module, and every module those
>> modules depend on, will have executed step 1-4, and have scopes that have
>> been created, and variables that have been declared (possibly with a value,
>> or possibly left uninitialized).
>>
>> So by the time you get to step 6, there isn't a "beyond the module
>> boundary", when you access the imported variables in your module, the JS
>> engine will reach across the module boundary for you, to get the current
>> value of the variable in the imported module. This behavior of reaching
>> across module scopes is what module syntax allows, and it is what enables
>> live binding.
>>
>> Because of this live behavior, if you imported something that was defined
>> with `let`, like your `let C;` example, it would cause a TDZ error because
>> the variable was still "uninitialized", whereas if you make it a `var`, it
>> will be initialized to `undefined`.
>>
>> > If I use the `var` method as you proposed (which is working in my
>> Babel env), should I expect that method to always work in any theoretical
>> 100%-implemented-to-spec ES6 environment, not just in Babel?
>>
>> Correct.
>>
>> On Tue, Aug 23, 2016 at 8:17 PM, /#!/JoePea <joe at trusktr.io> wrote:
>>
>>> > Damn, that's a Babel bug with the block scoping logic. That said, as
>>> in my example, that needs to be `var C;` anyway, `let` would throw (in an
>>> environment with working TDZ anyway). Changing it to `var` also stops the
>>> duplicate printing.
>>>
>>> Should I open an issue there? And I think you're right about it should
>>> throw, because it is strange that the function can be executed before the
>>> module is ever evaluated (that seems like it should be impossible), and
>>> therefore a TDZ error would happen because the `let` line wasn't
>>> theoretically evaluated yet.
>>>
>>> I don't see how it is possible with `var`. How is it that `var`s or
>>> `function`s can be hoisted *out of* the module? Is that part of spec? If
>>> so, then that is different hoisting from function-based hoisting of pre-ES6.
>>>
>>> I was under the impression that the modules were like a function, and
>>> hoisting would only happen inside the module. In that case, the `initC`
>>> function could not possibly be available until the `C` module itself was
>>> evaluated, so I was expecting for there to be an `undefined` error when
>>> `initC` was called before the `C` module was evaluated.
>>>
>>> You say that
>>>
>>> > which means you can import and call a function declaration from any
>>> module, even if that module hasn't started the `Evaluation` phase yet, the
>>> same way it'd work with other cases of hoisting, where execution hasn't
>>> reached the function declaration, but it is available early.
>>>
>>> Which makes sense based on what I see happening, but it seems strange
>>> because it means that the scope of the module (as far as hoisting is
>>> concerned) is not the module itself, but rather some outer scope that wraps
>>> *all* the modules that import a given symbol.
>>>
>>> You said,
>>>
>>> > the same way it'd work with other cases of hoisting, where execution
>>> hasn't reached the function declaration, but it is available early.
>>>
>>> Pre-ES6 "hoisting" in javascript happens on boundaries set by
>>> `function`s, and I thought that modules would be similar to function
>>> bodies, and therefore I thought that hoisting would be limited to within a
>>> module and did not expect hoisting to go beyond the module boundary to some
>>> scope that encompasses multiple modules. That to me is a different type of
>>> "hoisting" than what I know from pre-ES6 JavaScript's function-scope
>>> hoisting so it isn't necessarily the "same way it'd work with other cases
>>> of hoisting"; there is definitely some ES6-module-specific stuff happening
>>> that is a little different from pre-ES6 function-scope hoisting. (sidenote:
>>> I've asked the awesome Axel of 2ality to add these useful details to his
>>> articles.)
>>>
>>> If I use the `var` method as you proposed (which is working in my Babel
>>> env), should I expect that method to always work in any theoretical
>>> 100%-implemented-to-spec ES6 environment, not just in Babel?
>>>
>>> If so, then this may be one of the rare cases of "when we'd want to
>>> actually use `var` instead of `let`" besides for cases when we want pre-ES6
>>> hoisting which I think should be generally avoided in order to make code
>>> less error-prone and easier to understand. This behavior would have been
>>> nearly-impossible to know about without the knowledge gained from this
>>> conversation (or from reading the spec in depth which can be difficult).
>>>
>>>
>>>
>>> */#!/*JoePea
>>>
>>> On Tue, Aug 16, 2016 at 10:48 AM, Logan Smyth <loganfsmyth at gmail.com>
>>> wrote:
>>>
>>>> > Your `initC` solution is working in Meteor (Babel + Reify) and
>>>> Webpack+Babel, but the `initC` logic seems to run twice, as if there are
>>>> two C variables instead of one. The following code is based on yours, and
>>>> the `console.log('initC!!!')` statement unexpectedly executes twice, and
>>>> you'll see output like this:
>>>>
>>>> Damn, that's a Babel bug with the block scoping logic. That said, as in
>>>> my example, that needs to be `var C;` anyway, `let` would throw (in an
>>>> environment with working TDZ anyway). Changing it to `var` also stops the
>>>> duplicate printing.
>>>>
>>>> > I'm also not sure how `initC` can be defined when it is called in
>>>> the B module, which is evaluated before C and A. The evaluation order is B,
>>>> C, A (depth first). Does the `initC` function get hoisted into a scope
>>>> common with all three modules? That is the only way that would seem to
>>>> explain it, but that seems to go against the intuition I had that each
>>>> module had it's own module scope (as if it were wrapped inside a
>>>> `function() {}`, and therefore I thought the `initC` function would be
>>>> hoisted within the C module, and that with B being evaluated first I
>>>> thought an "undefined" error would be thrown when it tried to execute
>>>> `initC` (but that is not happening!). How is it that `initC` can be
>>>> available to the B module before C is evaluated?
>>>>
>>>> There are two separate pieces to executing a module, `Instantiation`,
>>>> and `Evaluation`, which are what comes into play here. When you tell a JS
>>>> environment to execute a file, it will instantiate every ES6 module in
>>>> dependency graph before beginning to execute _any_ of the modules. Babel
>>>> does its best to simulate this behavior, though it's not perfect at it. One
>>>> of the things that happens during module instantiation is that hoisted
>>>> declarations are initialized, which means you can import and call a
>>>> function declaration from any module, even if that module hasn't started
>>>> the `Evaluation` phase yet, the same way it'd work with other cases of
>>>> hoisting, where execution hasn't reached the function declaration, but it
>>>> is available early.
>>>>
>>>> This behavior is why you can't use `let C` there, because when `B` is
>>>> being evaluated, the `let C` line won't have run because the Evaluation
>>>> phase of `C` hasn't started yet. You can however access the `initC`
>>>> function because it is a function declaration. As long as there are no TDZ
>>>> errors in what you're doing, that function can do whatever it would like,
>>>> assuming it doesn't depend on other stuff that would require `Evaluation`
>>>> to have finished in `C`, the same as what happens with hoisting normally.
>>>> That means for instance you couldn't do
>>>>
>>>>     import B from './B';
>>>>     var SOME_CONSTANT = "hello";
>>>>
>>>>     export function initC(){
>>>>         return SOME_CONSTANT;
>>>>     }
>>>>
>>>> because calling `initC` here would return `undefined` if called from
>>>> inside a dependency cycle from `B`.
>>>>
>>>> On Sat, Aug 13, 2016 at 9:09 PM, /#!/JoePea <joe at trusktr.io> wrote:
>>>>
>>>>> Hi Logan,
>>>>>
>>>>> > The example I posted works properly with Babel's live-binding
>>>>> implementation and should require less repetition. What were your thoughts
>>>>> on it?
>>>>>
>>>>> Your `initC` solution is working in Meteor (Babel + Reify) and
>>>>> Webpack+Babel, but the `initC` logic seems to run twice, as if there are
>>>>> two C variables instead of one. The following code is based on yours, and
>>>>> the `console.log('initC!!!')` statement unexpectedly executes twice, and
>>>>> you'll see output like this:
>>>>>
>>>>> ```
>>>>> module B
>>>>> initC!!!
>>>>> module C
>>>>> initC!!!
>>>>> module A
>>>>> function A() { ... }
>>>>> function B() { ... }
>>>>> Entrypoint A {}
>>>>> ```
>>>>>
>>>>> I'm also not sure how `initC` can be defined when it is called in the
>>>>> B module, which is evaluated before C and A. The evaluation order is B, C,
>>>>> A (depth first). Does the `initC` function get hoisted into a scope common
>>>>> with all three modules? That is the only way that would seem to explain it,
>>>>> but that seems to go against the intuition I had that each module had it's
>>>>> own module scope (as if it were wrapped inside a `function() {}`, and
>>>>> therefore I thought the `initC` function would be hoisted within the C
>>>>> module, and that with B being evaluated first I thought an "undefined"
>>>>> error would be thrown when it tried to execute `initC` (but that is not
>>>>> happening!). How is it that `initC` can be available to the B module before
>>>>> C is evaluated?
>>>>>
>>>>> This is the code I have:
>>>>>
>>>>> ```js
>>>>> // --- Entrypoint
>>>>> import A from './A'
>>>>> console.log('Entrypoint', new A)
>>>>> ```
>>>>>
>>>>> ```js
>>>>> // --- Module A
>>>>>
>>>>> import C, {initC} from './C'
>>>>>
>>>>> console.log('module A')
>>>>> initC()
>>>>>
>>>>> class A extends C {
>>>>>     // ...
>>>>> }
>>>>>
>>>>> export {A as default}
>>>>> ```
>>>>>
>>>>> ```js
>>>>> // --- Module B
>>>>>
>>>>> import C, {initC} from './C'
>>>>>
>>>>> console.log('module B')
>>>>> initC()
>>>>>
>>>>> class B extends C {
>>>>>     // ...
>>>>> }
>>>>>
>>>>> export {B as default}
>>>>> ```
>>>>>
>>>>> ```js
>>>>> // --- Module C
>>>>>
>>>>> import A from './A'
>>>>> import B from './B'
>>>>>
>>>>> console.log('module C')
>>>>> let C
>>>>>
>>>>> export function initC(){
>>>>>     if (C) return
>>>>>
>>>>>     console.log('initC!!!')
>>>>>
>>>>>     C = class C {
>>>>>         constructor() {
>>>>>             // this may run later, after all three modules are
>>>>> evaluated, or
>>>>>             // possibly never.
>>>>>             console.log(A)
>>>>>             console.log(B)
>>>>>         }
>>>>>     }
>>>>> }
>>>>>
>>>>> initC()
>>>>>
>>>>> export {C as default}
>>>>> ```
>>>>>
>>>>> */#!/*JoePea
>>>>>
>>>>> On Thu, Aug 11, 2016 at 10:26 AM, Logan Smyth <loganfsmyth at gmail.com>
>>>>> wrote:
>>>>>
>>>>>> Keep in mind `let A = A;` is a TDZ error in any real ES6
>>>>>> environment.
>>>>>>
>>>>>> The example I posted works properly with Babel's live-binding
>>>>>> implementation and should require less repetition. What were your thoughts
>>>>>> on it?
>>>>>>
>>>>>> On Thu, Aug 11, 2016 at 12:23 AM, /#!/JoePea <joe at trusktr.io> wrote:
>>>>>>
>>>>>>> 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/meteor/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
>>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> _______________________________________________
>>>>>>> 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/20161008/446f8d13/attachment-0001.html>


More information about the es-discuss mailing list