JavaScript Script Type Module Loading and Execution
Using <script type="module"> in modern web
development fundamentally changes how browsers fetch, parse, and execute
JavaScript files compared to classic scripts. Setting the script type to
a module automatically activates deferred execution, enforces strict
mode, encapsulates code within local module scopes, handles dependency
graphs asynchronously, and requires cross-origin security checks.
Automatic Deferred Execution
Classic <script> tags block HTML parsing by
default unless configured with defer or async
attributes. In contrast, <script type="module"> is
automatically deferred.
The browser downloads the module script and all of its imported
dependencies in parallel with HTML parsing. The script’s execution is
delayed until the HTML document has finished parsing, running just
before the DOMContentLoaded event fires.
Native Module Scoping and Strict Mode
Classic scripts execute in the global scope, meaning top-level
variables and functions attach directly to the window
object.
Module scripts introduce their own lexical scope: *
Module-Level Scope: Top-level variables, functions, and
classes are private to the module file unless explicitly shared using
export. * Automatic Strict Mode: All code
within a module script runs in "use strict" mode by
default, eliminating the need to declare it manually. *
this Binding: The top-level
this value evaluates to undefined instead of
referencing the window object.
Asynchronous Dependency Resolution
When a module uses import statements, the browser treats
the code as a dependency graph:
- Parsing: The browser scans the entry script for
importstatements. - Fetching: All imported modules and their sub-dependencies are fetched over the network concurrently.
- Execution Order: The browser waits until the entire dependency tree is fully downloaded and parsed before executing the files. Execution proceeds depth-first, ensuring dependencies run before the files that import them.
Single Execution (Singleton Evaluation)
If a module script or an imported module file is included multiple times across a webpage, the browser downloads and executes it only once. Subsequent imports reuse the same cached module instance, preventing duplicate execution and state conflicts.
CORS Requirements
Module scripts are subject to Cross-Origin Resource Sharing (CORS)
policies. Unlike classic scripts, external module scripts fetched from
different domains must include valid
Access-Control-Allow-Origin headers. Additionally, module
scripts cannot be loaded directly from the local filesystem
(file://) due to CORS restrictions, requiring a local or
remote web server.
The async Attribute
on Modules
While module scripts default to deferred behavior, the
async attribute can be explicitly added via
<script type="module" async>. When async
is applied: * The module and its imported dependencies load in the
background. * The script executes immediately once all dependencies are
loaded, regardless of whether HTML parsing is complete.