ES Module Scripts type=module
Load JavaScript as ES modules with type=module.
ES Module Scripts type=module is a free HTML Academy lesson on CoddyKit — lesson 1 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the HTML Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
What Are ES Modules?
An ES module is a JavaScript file that uses import and export declarations. Modules have their own scope (no global pollution), strict mode by default, and explicit dependencies — fixing decades of script-tag-ordering problems.
The Module Script Tag
<script type="module" src="app.js"> tells the browser the file is a module. The browser parses imports, fetches dependencies in parallel, and only executes the entry once the entire dependency graph is downloaded and compiled.
<script type="module" src="app.js"></script>Modules are Deferred
Module scripts behave as if they had defer: they download in parallel with HTML parsing and execute after parsing in declaration order. You can place <script type="module"> anywhere (even in <head>) without blocking the page.
Imports Use Specifiers
An import statement uses a specifier — either a relative URL (./utils.js), an absolute URL (https://cdn.example.com/lib.js), or a bare name (lodash). Bare names require an import map (covered next) because the browser does not know which file they map to.
// app.js
import { sum } from "./utils.js";
import { render } from "https://esm.sh/preact";
console.log(sum(1, 2));File Extensions Are Required
Browsers do not auto-add .js to import specifiers. import "./utils" fails; import "./utils.js" works. Bundlers and Node may be more forgiving; the browser is strict so write the extension explicitly.
CORS Required
Modules are always fetched with CORS, even when same-origin. Cross-origin module files must serve the appropriate Access-Control-Allow-Origin header or the import fails. Most CDNs (esm.sh, jsdelivr, unpkg) configure this correctly out of the box.
Top-Level Await
Modules support await at the top level — no async-function wrapper required: const data = await fetch("/api").then(r => r.json()). The module's consumers wait until the top-level await resolves before they execute.
// data.js
export const config = await fetch("/config.json").then(r => r.json());
// app.js (waits for data.js)
import { config } from "./data.js";
console.log(config);Modules Are Singletons
A module is evaluated exactly once per session regardless of how many other modules import it. The exports object is shared — every consumer sees the same instance, which makes modules a clean way to share singletons like a configuration object or a state store.
Inline Modules
You can also write modules inline: <script type="module">import x from "./y.js"; ...</script>. Useful for bootstrap code or experiments, though external files are easier to debug and cache.
nomodule for Legacy Fallback
Pair a <script type="module"> with a <script nomodule src="legacy.js">. Modern browsers run the module and ignore the nomodule script; legacy browsers run the nomodule script and ignore the module. Used during the migration to all-ESM apps.
Errors and import Failures
An import that fails (404, CORS, syntax error) throws and prevents the entire module graph from executing. Use the Network panel to spot failed module requests and the Console to read the actual import error message.
Knowledge Check
Why do module scripts behave as if defer were set without you specifying it?
Summary
<script type="module"> loads ES modules — strict-mode files with import/export declarations that resolve a dependency graph. Modules defer by default, require explicit file extensions, are CORS-fetched, are evaluated as singletons, and support top-level await. Use nomodule for legacy fallback and watch for missing file extensions when imports silently fail.
Frequently asked questions
Is the “ES Module Scripts type=module” lesson free?
Yes — the full text of “ES Module Scripts type=module” is free to read here on the web, and the HTML Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the HTML Academy course, upgrade to CoddyKit PRO.
What will I learn in “ES Module Scripts type=module”?
Load JavaScript as ES modules with type=module. You practise HTML Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start HTML Academy?
No prior experience is required. HTML Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 1 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “ES Module Scripts type=module” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this HTML Academy lesson?
Yes. Every HTML Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- ES Module Scripts type=module
- Import Maps importmap
- Dynamic Import() in Modules
- Module Federation Basics