Sitemap

Understanding type="module" in JavaScript: A Comprehensive Guide

3 min readJun 5, 2024
Photo by Sirma Krusteva on Unsplash

JavaScript has evolved to include features that make coding more modular and maintainable. One such feature is the use of ES6 modules with type="module". In this blog, we will explore what type="module" is, its features, and how it behaves in different scenarios.

What We Will Cover

  • Introduction to type="module"
  • Features of ES6 Modules
  • Behavior of Non-modular vs. Modular Scripts
  • Complex Import Scenarios
  • Summary of Key Points

Introduction to type="module"

When you include a JavaScript file in an HTML document, you typically do this:

<script src="script.js"></script>

With ES6 modules, you can use:

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

This tells the browser that the script is a module. Let’s dive into what this means.

Features of ES6 Modules

  1. Scoped Variables: Variables declared in a module are not global; they are scoped to that module.
  2. Import and Export: You can export functions, objects, or values from a module and import them into other modules.
  3. Deferred Execution: Module scripts are executed after the HTML document is fully parsed.
  4. Single Execution: Modules are only executed once, even if imported multiple times.

Behavior of Non-modular vs. Modular Scripts

Let’s look at an example to understand the differences.

Non-modular Scripts

Consider two scripts, script1.js and script2.js, both defining a function greet.

script1.js:

function greet() {
console.log("Hello from script1!");
}
greet();

script2.js:

function greet() {
console.log("Hello from script2!");
}
greet();

HTML:

<script src="script1.js"></script>
<script src="script2.js"></script>

In this case, the greet function in script2.js overwrites the one in script1.js. The output will be:

Hello from script2!
Hello from script2!

Modular Scripts

Now, let’s change the scripts to use modules.

HTML:

<script type="module" src="script1.js"></script>
<script type="module" src="script2.js"></script>

Since each module has its own scope, the greet functions do not conflict. The output will be:

Hello from script1!
Hello from script2!

Complex Import Scenarios

Let’s explore a more complex scenario with three scripts.

script1.js:

import { functionFromScript2 } from './script2.js';
import { functionFromScript3 } from './script3.js';

console.log("This is from script1");
functionFromScript2();
functionFromScript3();

script2.js:

import { functionFromScript3 } from './script3.js';
console.log("This is from script2");
export function functionFromScript2() {
console.log("Function from script2");
functionFromScript3();
}

script3.js:

console.log("This is from script3");
export function functionFromScript3() {
console.log("Function from script3");
}

HTML:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Module Example</title>
</head>
<body>
<script type="module" src="script1.js"></script>
</body>
</html>

Detailed Explanation

When the HTML file is loaded, the browser will execute the module scripts. Here’s a step-by-step breakdown:

  1. script1.js Starts Execution
  • The browser encounters the import statements in script1.js.
  • script1.js imports script2.js.

2. script2.js Starts Execution

  • script2.js starts executing.
  • script2.js imports script3.js.

3. script3.js Starts Execution

  • script3.js starts executing.
  • It logs “This is from script3” to the console.
  • Execution of script3.js completes.

4. script2.js Resumes Execution

  • After importing script3.js, script2.js continues execution.
  • It logs “This is from script2” to the console.
  • It exports the functionFromScript2 function.

5. script1.js Resumes Execution

  • After importing script2.js, script1.js imports script3.js again.
  • Since script3.js has already been executed, it does not log again.
  • script1.js continues execution and logs “This is from script1” to the console.
  • It calls functionFromScript2 from script2.js.

6. functionFromScript2 Execution

  • functionFromScript2 logs “Function from script2” to the console.
  • It calls functionFromScript3 from script3.js.
  • functionFromScript3 logs “Function from script3” to the console.

7. functionFromScript3 Execution in script1.js

  • script1.js calls functionFromScript3 from script3.js again.
  • functionFromScript3 logs “Function from script3” to the console again.

Final Output

The final console output will be:

This is from script3
This is from script2
This is from script1
Function from script2
Function from script3
Function from script3

Why This Happens

  1. Single Execution: script3.js is executed only once, even though it is imported twice (by script1.js and script2.js).
  2. Sequential Import and Execution: The order of import statements determines the order of script execution.
  3. Function Calls Across Modules: Functions exported from one module and called from another execute as expected, maintaining their own scope and context.

Summary of Key Points

  • Scoped Variables: Each module has its own scope, preventing conflicts.
  • Import and Export: Modules can export and import functionality, promoting code reuse.
  • Deferred Execution: Module scripts execute after the HTML is fully parsed.
  • Single Execution: Modules are executed only once, even if imported multiple times.
  • Better Dependency Management: Modules make it clear what dependencies exist and manage them efficiently.

By using type="module" in JavaScript, you can write cleaner, more maintainable, and modular code. Understanding these concepts helps you leverage the full power of ES6 modules in your projects.

--

--

Neeraj Dana
Neeraj Dana

Written by Neeraj Dana

Top Writer in Javascript React Angular Node js NLP Typescript Machine Learning Data science Maths

No responses yet