Dynamic imports
Import function
As mentioned before, it is not possible to use import
inside a block statement.
So, it is not possible to import conditionally or via a function like an event handler.
However, there would obviously be performance benefits if we could load modules only when they are needed, rather than loading everything in advance.
A recent addition to JavaScript allows you to call an import()
function, taking the path to the module as an argument.
This allows dynamic imports.
Function import()
returns a promise, which fulfills with a
module object that contains all its exports:
<script>
import("./modules/moduleA.js").then((module) => {
console.log(module.someVar); // logs: "someValueA"
});
</script>
Note that dynamic imports, such as in the example above, can be used in a <script>
element that does not have a type="module"
attribute.
However, top level await
is only available in async
functions and modules.
// pi.js
const pi = Math.PI;
const tau = function() { return pi * 2; };
export { pi, tau };
<script type="module">
const { pi, tau } = await import("./modules/pi.js");
console.log(pi); // logs: 3.141592653589793
console.log(tau()); // logs: 6.283185307179586
</script>
Now we can, for instance, include an import function in an event handler:
// greetings.js
export function welcome(user) {
return `Hello ${user}, nice to meet you!`;
}
const sayHelloButton = document.querySelector("#sayHello");
const sayHelloOutput = document.querySelector("#sayHelloOutput");
let user = "John Doe";
sayHelloButton.addEventListener("click", () => {
user = prompt("What's your name?");
import("./modules/greetings.js")
.then(module =>
sayHelloOutput.textContent = module.welcome(user))
.catch(error => console.error(error));
});
Top level await
As mentioned before, top level await
is available within modules.
We can use it for an input function:
// getPI.js
export default function() { return Math.PI };
<script type="module">
const {default: pi} = await import('./modules/getPI.js');
console.log(pi()); // logs: 3.141592653589793
</script>
But we can also use await
for a dynamic export:
// getProducts.js
const products = fetch("https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json")
.then((response) => response.json());
export default await products;
<script type="module">
import products from "./modules/getProducts.js";
console.log(products[0].name); // logs: "baked beans"
</script>
In the example above await
in module getProducts.js
returns the value (or error) promise products
resolves (or rejects) with.
Any other modules which import products
will wait executing until products
has been downloaded and parsed,
without blocking the download of other modules.