Export and import statements that we covered in previous chapters are called âstaticâ. The syntax is very simple and strict.
First, we canât dynamically generate any parameters of import.
The module path must be a primitive string, canât be a function call. This wonât work:
import ... from getModuleName(); // Error, only from "string" is allowed
Second, we canât import conditionally or at run-time:
if(...) {
import ...; // Error, not allowed!
}
{
import ...; // Error, we can't put import in any block
}
Thatâs because import/export aim to provide a backbone for the code structure. Thatâs a good thing, as code structure can be analyzed, modules can be gathered and bundled into one file by special tools, unused exports can be removed (âtree-shakenâ). Thatâs possible only because the structure of imports/exports is simple and fixed.
But how can we import a module dynamically, on-demand?
The import() expression
The import(module) expression loads the module and returns a promise that resolves into a module object that contains all its exports. It can be called from any place in the code.
We can use it dynamically in any place of the code, for instance:
let modulePath = prompt("Which module to load?");
import(modulePath)
.then(obj => <module object>)
.catch(err => <loading error, e.g. if no such module>)
Or, we could use let module = await import(modulePath) if inside an async function.
For instance, if we have the following module say.js:
// ð say.js
export function hi() {
alert(`Hello`);
}
export function bye() {
alert(`Bye`);
}
â¦Then dynamic import can be like this:
let {hi, bye} = await import('./say.js');
hi();
bye();
Or, if say.js has the default export:
// ð say.js
export default function() {
alert("Module loaded (export default)!");
}
â¦Then, in order to access it, we can use default property of the module object:
let obj = await import('./say.js');
let say = obj.default;
// or, in one line: let {default: say} = await import('./say.js');
say();
Hereâs the full example:
export function hi() {
alert(`Hello`);
}
export function bye() {
alert(`Bye`);
}
export default function() {
alert("Module loaded (export default)!");
}<!doctype html>
<script>
async function load() {
let say = await import('./say.js');
say.hi(); // Hello!
say.bye(); // Bye!
say.default(); // Module loaded (export default)!
}
</script>
<button onclick="load()">Click me</button>Dynamic imports work in regular scripts, they donât require script type="module".
Although import() looks like a function call, itâs a special syntax that just happens to use parentheses (similar to super()).
So we canât copy import to a variable or use call/apply with it. Itâs not a function.
Comments
<code>tag, for several lines â wrap them in<pre>tag, for more than 10 lines â use a sandbox (plnkr, jsbin, codepenâ¦)