From ReferenceError: can't access lexical declaration 'X' before initialization - JavaScript | MDN, there is an example of invalid import:
a.js
(entry module):
import { b } from "./b.js";
export const a = 2;
b.js
:
import { a } from "./a.js";
console.log(a); // ReferenceError: Cannot access 'a' before initialization
export const b = 1;
MDN explains:
In this example, the imported variable
a
is accessed but is uninitialized, because the evaluation ofa.js
is blocked by the evaluation of the current moduleb.js
.
I understand this as importing a module means embedding the code of the module at the line of the import statement. That is, the a.js
becomes this at compile time:
console.log(a); // ReferenceError: Cannot access 'a' before initialization
const b = 1;
const a = 2;
Is this understanding correct? I don't see it's explained in import - JavaScript | MDN. I don't know how to test this because reordering the lines in a.js
doesn't change the result due to hoisting.
The code from an imported module is not simply embedded ("pasted"), but lives in a separate closure. Although this is surely an oversimplification, I compare the module with a function and the export
statement with its return
statement:
function a_js() {
var b = b_js(); // unnecessary line
return 2;
}
function b_js() {
var a = a_js();
console.log(a);
return 1;
}
<button onclick="a_js()">import a.js</button>
<button onclick="b_js()">import b.js</button>
Because the modules import each other, they cannot be loaded in any order: Pressing either button leads to a "Maximum call stack size exceeded" error.
But if you remove the unnecessary line (which only fills a local variable that is then discarded), it works.