Modifying ES6 module exports
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?
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 > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20151221/9f74e5ce/attachment.html>
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.
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 > >
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>
circular dependencies will work nicely with declarations, not so much with expressions because the code has to be evaluated to set those bindings. This, of course, is not a problem if you're not invoking some initialization when evaluating the body of the module.
all in all, that's what you're experiencing. as for the {}, that's just babel.
side note: this has nothing to do with those being default exports, it will happen for any export.
circular dependencies will work nicely with declarations, not so much with expressions because the code has to be evaluated to set those bindings. This, of course, is not a problem if you're not invoking some initialization when evaluating the body of the module. all in all, that's what you're experiencing. as for the {}, that's just babel. side note: this has nothing to do with those being default exports, it will happen for any export. /caridy > On Dec 21, 2015, at 10: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
The {}
shouldn't be from Babel, it has handled all circular dependency
cases as far as I'm aware. I'm curious to know what the end cause of this
issue is, but this isn't really the right discussion forum for it. Joe, if
you do end up making a simplified example that can be tested, I'd be happy
to take a look, so feel free to ping me.
The `{}` shouldn't be from Babel, it has handled all circular dependency cases as far as I'm aware. I'm curious to know what the end cause of this issue is, but this isn't really the right discussion forum for it. Joe, if you do end up making a simplified example that can be tested, I'd be happy to take a look, so feel free to ping me. On Tue, Dec 22, 2015 at 5:49 PM, Caridy Patino <caridy at gmail.com> wrote: > circular dependencies will work nicely with declarations, not so much with > expressions because the code has to be evaluated to set those bindings. > This, of course, is not a problem if you're not invoking some > initialization when evaluating the body of the module. > > all in all, that's what you're experiencing. as for the {}, that's just > babel. > > side note: this has nothing to do with those being default exports, it > will happen for any export. > > /caridy > > > On Dec 21, 2015, at 10: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/b04ba30e/attachment.html>
Cool, thanks guys. Indeed that appears to have been my problem.
Cool, thanks guys. Indeed that appears to have been my problem. On Tue, Dec 22, 2015 at 10:59 PM, Logan Smyth <loganfsmyth at gmail.com> wrote: > The `{}` shouldn't be from Babel, it has handled all circular dependency > cases as far as I'm aware. I'm curious to know what the end cause of this > issue is, but this isn't really the right discussion forum for it. Joe, if > you do end up making a simplified example that can be tested, I'd be happy > to take a look, so feel free to ping me. > > On Tue, Dec 22, 2015 at 5:49 PM, Caridy Patino <caridy at gmail.com> wrote: >> >> circular dependencies will work nicely with declarations, not so much with >> expressions because the code has to be evaluated to set those bindings. >> This, of course, is not a problem if you're not invoking some initialization >> when evaluating the body of the module. >> >> all in all, that's what you're experiencing. as for the {}, that's just >> babel. >> >> side note: this has nothing to do with those being default exports, it >> will happen for any export. >> >> /caridy >> >> > On Dec 21, 2015, at 10: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 > >
Actually, Babel defers circular dependencies to the underlying module resolver, so most likely Node/Browserify/etc. is where you're getting that, as that's actually intentional, documented behavior in Node.
Actually, Babel defers circular dependencies to the underlying module resolver, so most likely Node/Browserify/etc. is where you're getting that, as that's actually intentional, documented behavior in Node. On Wed, Dec 23, 2015, 20:24 /#!/JoePea <joe at trusktr.io> wrote: > Cool, thanks guys. Indeed that appears to have been my problem. > > On Tue, Dec 22, 2015 at 10:59 PM, Logan Smyth <loganfsmyth at gmail.com> > wrote: > > The `{}` shouldn't be from Babel, it has handled all circular dependency > > cases as far as I'm aware. I'm curious to know what the end cause of this > > issue is, but this isn't really the right discussion forum for it. Joe, > if > > you do end up making a simplified example that can be tested, I'd be > happy > > to take a look, so feel free to ping me. > > > > On Tue, Dec 22, 2015 at 5:49 PM, Caridy Patino <caridy at gmail.com> wrote: > >> > >> circular dependencies will work nicely with declarations, not so much > with > >> expressions because the code has to be evaluated to set those bindings. > >> This, of course, is not a problem if you're not invoking some > initialization > >> when evaluating the body of the module. > >> > >> all in all, that's what you're experiencing. as for the {}, that's just > >> babel. > >> > >> side note: this has nothing to do with those being default exports, it > >> will happen for any export. > >> > >> /caridy > >> > >> > On Dec 21, 2015, at 10: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 > > > > > _______________________________________________ > 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/20151225/af1d9765/attachment.html>
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:
// A.js import B from './B' let A = window.globalThing export default A // modify the A object adding methods that reference B.
// 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:
// 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:
// A.js import B from './B' let A = window.globalThing export default A A.setup = () => { // modify the A object adding methods that reference B. }
// 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:// 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?