Skip to main content

JavaScript Modules

JavaScript Dynamic Import

Written by Published

import() loads a module while the program is running, returning a promise.

The static import loads everything up front.

import() loads only when you actually call it.

Example

Example

javascript

// Simulating a dynamic import with a promise, since there is
// no second file to load here.
function importMathModule() {
  return Promise.resolve({
    double: function (n) { return n * 2; }
  });
}

importMathModule().then(function (module) {
  console.log(module.double(5));
});

The output is 10, arriving through a promise.

How Dynamic Import Works

import("./path.js") returns a promise.

The promise resolves to the module's exports, as one object.

It can be called from anywhere, including inside an if.

Syntax

Syntax

javascript

const module = await import("./math.js");
module.double(5);

Unlike static import, this needs no type="module" on the calling script.

Using await

Inside an async function, this reads almost like requiring a file.

Example

Example

javascript

function importMathModule() {
  return Promise.resolve({ double: function (n) { return n * 2; } });
}

async function run() {
  const math = await importMathModule();
  return math.double(21);
}

run().then(function (result) {
  console.log(result);
});

The output is 42.

Loading Conditionally

This is the main reason dynamic import exists.

Code the visitor never needs is never downloaded.

Example

Example

javascript

function importChartModule() {
  return Promise.resolve({ render: function () { return "chart rendered"; } });
}

async function maybeShowChart(showChart) {
  if (!showChart) {
    return "chart module never loaded";
  }
  const chart = await importChartModule();
  return chart.render();
}

maybeShowChart(true).then(function (result) {
  console.log(result);
});
maybeShowChart(false).then(function (result) {
  console.log(result);
});

A heavy charting library only loads for visitors who need a chart.

Handling a Failed Import

A missing or broken module rejects the promise, so wrap it normally.

Example

Example

javascript

function importBrokenModule() {
  return Promise.reject(new Error("module not found"));
}

async function run() {
  try {
    await importBrokenModule();
    return "loaded";
  } catch (error) {
    return "failed: " + error.message;
  }
}

run().then(function (result) {
  console.log(result);
});

The output is failed: module not found.

Destructuring the Result

The resolved value is the module's whole export object.

Example

Example

javascript

function importShapesModule() {
  return Promise.resolve({
    square: function (s) { return s * s; },
    circle: function (r) { return Math.round(Math.PI * r * r); }
  });
}

importShapesModule().then(function ({ square, circle }) {
  console.log(square(4) + " and " + circle(3));
});

Destructuring in the then parameter pulls out just what is needed.

Static Versus Dynamic

Static import is analysed before anything runs, which enables optimisations.

Dynamic import() trades that for flexibility and lazy loading.

Example

Example

javascript

function importMathModule() {
  return Promise.resolve({ double: function (n) { return n * 2; } });
}

console.log(typeof importMathModule());

The output is object: it is a promise, available immediately.

Complete Example

Complete Example

html

<!DOCTYPE html>
<html>
<head>
  <title>Dynamic Import</title>
</head>
<body>

  <h1>Dynamic Import</h1>

  <button id="load">Load the chart module</button>
  <p id="out">Not loaded yet</p>

  <script type="module">
    document.getElementById("load").addEventListener("click", async function () {
      const out = document.getElementById("out");
      out.textContent = "Loading...";

      try {
        const chart = await import("./chart.js");
        out.textContent = chart.render();
      } catch (error) {
        out.textContent = "Could not load the chart module";
      }
    });
  </script>

</body>
</html>

Try It Yourself

Real dynamic import needs a second file to load.

Try the simulated version:

Run the conditional loading example with both true and false.

Important Points

  • import() returns a promise for the module's exports.
  • It can run anywhere, unlike static import.
  • It enables loading code only when it is actually needed.
  • A failed import rejects the promise.
  • Static import is analysed upfront; dynamic import is flexible but lazy.

Conclusion

Dynamic import is the standard way to split code and load it on demand.

It is genuinely just a promise, so every promise technique already covered applies.

Conditional loading is where it earns its place in a real application.