Modifying ES6 module exports

Ryan Dunckel sparty02 at gmail.com
Tue Dec 22 12:58:55 UTC 2015


Related: http://www.2ality.com/2015/07/es6-module-exports.html?m=1
On Tue, Dec 22, 2015 at 4:02 AM /#!/JoePea <joe at trusktr.io> wrote:

> In my case I was using Webpack+babel-loader. I guess that makes sense,
> about the run-time dependencies. After solving the problem by wrapping
> the module logic for A and B in functions then calling those functions
> in main.js. I then encountered another problem: package C imports the
> default from package B, and at initialization-time B is undefined in C
> even though there's no circular dependency there. I was able to solve
> that problem by wrapping init-time logic in a function and again
> executing that in main.js. So, basically, moving all to calls in
> main.js solved both of these problems. I can follow what you're saying
> about the circular dep between A and B, but I'm not at all sure why B
> would be undefined in C after having moved A and B logic to main.js,
> leaving C logic still in the C module.
>
> On Mon, Dec 21, 2015 at 8:05 PM, Logan Smyth <loganfsmyth at gmail.com>
> wrote:
> > To start, an object is definitely not what I'd expect. The core thing to
> > remember with ES6 modules is that while imports are live bindings, you
> still
> > need to write your code in such a way that it has no run-time circular
> > dependencies.
> >
> > In your specific examples, you are importing `A` first, which will begin
> `B`
> > loading. Since `A` has not finished executing yet, and B will be
> attempting
> > to access the the `A` import before the `A.js` file has begin executing.
> I'm
> > not 100% sure off the top of my head, but in a real ES6 environment, that
> > would either result in the `A` import being `undefined`, or attempting to
> > access it would throw a temporal dead zone error due to you accessing a
> > variable before it has been initialized.
> >
> > If your `A.js` file comment "// modify the A object adding methods that
> > reference B." adds those references without actually accessing `B` in any
> > way, then the solution to your issue (in a real environment anyway)
> would be
> > to import `B.js` _first_ so that you do not have circular
> > initialization-time dependencies.
> >
> > In this case, are you using Babel's ES6 module syntax transpiling, or
> > Webpack with another transpiler?
> >
> >
> > On Mon, Dec 21, 2015 at 7:25 PM, /#!/JoePea <joe at trusktr.io> wrote:
> >>
> >> 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?
> >> _______________________________________________
> >> es-discuss mailing list
> >> es-discuss at mozilla.org
> >> https://mail.mozilla.org/listinfo/es-discuss
> >
> >
> _______________________________________________
> 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/20151222/8fa84a09/attachment.html>


More information about the es-discuss mailing list