Recently I came across an eslint warning in my project about a circular dependency. I previously thought circular references are impossible in ES modules. But apparently they work in some situations.
I tried to reproduce the minimal working example of a circular dependency.
This works:
// module-a.mjs
import { b } from "./mb.mjs";
export const a = 1;
export function fa() {
console.log(b);
}
setTimeout(() => {
fa();
});
// module-b.mjs
import { a } from "./ma.mjs";
export const b = 2;
export function fb() {
console.log(a);
}
setTimeout(() => {
fb();
});
but the same code above without setTimeouts
throws error, or to make it simpler, the code below does not work:
// module-a.mjs
import { b } from "./mb.mjs";
export const a = 1;
console.log(b);
// module-b.mjs
import { a } from "./ma.mjs";
export const b = 2;
console.log(a);
The error would be:
Uncaught ReferenceError: Cannot access 'a' before initialization
My questions are:
- what criteria should there be for a circular reference to work? Why my first example works and the second one does not? Although they are both circularly dependent.
- How does ES modules handle this recursive situation?
I’ve seen this explanation about recursive require
s in NodeJS documentation, but not sure if that also applies to ES modules or not: https://nodejs.org/api/modules.html#modules_cycles . Does ES modules use the exact same mechanism as described here?