Skip to main content

JavaScript Modules

JavaScript Module Scripts

Written by Updated

A script becomes a module by adding type="module" to its tag.

Without it, import and export are syntax errors.

The attribute also changes a few things about how the script loads.

Example

Example

javascript

// Demonstrating the behaviour a module script gives you,
// without needing a real module file.
console.log("this simulates a deferred module script");

A module script behaves like a normal deferred script, described below.

What type="module" Changes

It enables import and export.

The script is deferred automatically, without needing the defer attribute.

It always runs in strict mode.

Syntax

Syntax

html

<script type="module" src="main.js"></script>

Or inline: <script type="module">...</script>.

Automatically Deferred

A module script waits for the HTML to be parsed before running.

An ordinary script without defer runs immediately, which can be too early.

Example

Example

javascript

function readTitle() {
  return typeof document !== "undefined" ? "would read the page here" : "no document";
}

console.log(readTitle());

A module script placed anywhere on the page can safely look for elements.

Runs Once, However Many Times It Is Included

Two script tags pointing at the same module file share one execution.

Example

Example

javascript

let loadCount = 0;

function simulateModuleLoad() {
  loadCount++;
  return "module content";
}

const first = simulateModuleLoad();
const second = first;

console.log(loadCount);

A real browser caches a module by its URL and only runs it once.

CORS for Cross-Origin Modules

Importing a module from a different origin needs that server to allow it.

Ordinary scripts do not have this restriction.

Example

Example

javascript

console.log("cross-origin modules need a CORS-friendly server response");

This mainly matters when loading modules from a CDN.

No Module Scripts from file://

Opening an HTML file directly usually blocks module imports.

A local development server is the normal fix.

Example

Example

javascript

console.log("module scripts generally need http:// or https://, not file://");

This is one of the most common reasons a first module attempt fails silently.

nomodule for Old Browsers

A script with nomodule is ignored by a browser that understands modules.

It runs only in browsers that do not, giving a fallback path.

Example

Example

javascript

console.log("nomodule scripts are skipped by module-aware browsers");

This pattern is far less needed now that modules are widely supported.

Complete Example

Complete Example

html

<!DOCTYPE html>
<html>
<head>
  <title>Module Scripts</title>
</head>
<body>

  <h1>Loaded as a module</h1>
  <p id="out"></p>

  <script type="module">
    document.getElementById("out").textContent = "Module script ran";
  </script>

</body>
</html>

Try It Yourself

Run the above example in the Try It Editor.

Try removing type="module":

Take out the attribute; the script still works here since it uses no import.

Important Points

  • type="module" enables import and export.
  • A module script is deferred automatically.
  • A module runs once, no matter how many times it is included.
  • Cross-origin modules need CORS.
  • Module scripts generally need a real server, not file://.

Conclusion

The module attribute changes more than just the syntax it allows.

Automatic deferral and single execution are worth knowing on their own.

The file:// restriction is the classic reason a first attempt fails.