Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

what is the meaning of static import in ES6?

Tags:

javascript

One major advantage in ESM over CJS is how ESM has — and encourages — a way of statically importing dependencies. Static imports vastly improve the introspection capabilities of module systems, given they can be analyzed statically and lexically extracted from the abstract syntax tree (AST) of each module in the system

— Mastering Modular JavaScript by Nicolas Bevacqua

i do not understand this ,anyone can help?

like image 574
forks Hume Avatar asked Oct 16 '25 03:10

forks Hume


1 Answers

JavaScript's native module system, sometimes called ESM (ECMAScript Modules), has both static and dynamic import. It started with just static import (which is still dominant), and then dynamic import was added by the dynamic import proposal, which is now complete and well-supported in browsers, Node.js, and bundlers (though some bundlers add restrictions if you want them to do tree-shaking).

What do we mean by "static"? When you use an import declaration, it must be at the top level of the module, outside of any control-flow statements, and it must use a string literal to say what module to import from, not just a string. That's so the relationship between modules can be determined by static analysis (by just parsing the code, without running it). This is valid:

import foo from "./mod.js";

That's a static import.

This is not valid:

// Invalid (but keep reading for an alternative)
if (someCondition) {
    import foo from "./mod1.js";
} else {
    import foo from "./mod2.js";
}

Nor this:

// Invalid (but keep reading for an alternative)
import foo from someCondition ? "./mod1.js" : "./mod2.js";

If that worked, it would be a dynamic import; what you're importing varies depending on a condition determined at runtime. (JavaScript does have dynamic import now, just not with that syntax, more below.)

And similarly, exports are declared with static export declarations, not runtime code.

CommonJS (CJS, a variant of which is used by Node.js) has only dynamic import and export, via the require function and assignment to the exports object:

// Valid CommonJS
let foo;
if (someCondition) {
    foo = require("./mod1.js");
} else {
    foo = require("./mod2.js");
}

// or more simply:

const foo = require(someCondition ? "./mod1.js" : "./mod2.js");

Because there are situations where determining your import at runtime is useful, JavaScript also has dynamic import now via something that looks like a function call (but isn't):

// Valid ESM (now that dynamic import is done)
import(someCondition ? "./mod1.js" : "./mod2.js")
.then(({default: foo}) => {
    // ...code here using `foo` from either `mod1` or `mod2`...
});

The import() pseudo-function returns a promise which is either fulfilled with the module namespace object for the module (which has the module's exports as properties), or is rejected with an error.

The dynamic import() pseudo-function combines particularly well with top-level await. Top-level await likes you write the above like this:

// Valid ESM (now that dynamic import and top-level `await` are done)
const foo = await import(someCondition ? "./mod1.js" : "./mod2.js").default;
// ...code here using `foo` from either `mod1` or `mod2`...

Exports are still statically defined, though you could always export an object with runtime-defined properties.


Looking at the examples of dynamic import, you may be thinking: "Hey, he's left off rejection handlers! If there's a problem loading the module, he'll get an "unhandled rejection" error in the console!" Yup, I will. It'll be next to the module loading error that's already there, and possibly the network error that caused the module load to fail. Which is what you would get if a static module load failed, too (just without the unhandled rejection error). Module load failure is a fairly catastrophic thing. :-) But if you have something optional, you could certainly handle rejection:

let localization;
try {
    // Try to get localization information for the user's language...
    localization = import(`./locale-${navigator.language}.js`);
} catch {
    // ...that failed, fall back to default
    localization = import(`./locale-default.js`);
}

(The sharp-eyed will note that the above uses optional catch binding syntax.)

like image 106
T.J. Crowder Avatar answered Oct 17 '25 17:10

T.J. Crowder