ECMAScript Modules
What is ESM?
- ESM stands for ECMAScript Modules, which is the official standard for modular JavaScript defined in the ECMAScript specification (ES6/ES2015 and later).
- ESM allows you to split JavaScript code into separate files (modules) that can import and export values (functions, classes, variables, etc.) between each other.
- This makes code easier to organize, reuse, and maintain.
Syntax Example
math.js
export function add(a, b) {
return a + b;
}
main.js
import { add } from './math.js';
console.log(add(2, 3)); // 5
- Uses import and export keywords.
- Static structure — imports/exports are determined at compile time (not dynamically).
- In ESM, the JavaScript engine can figure out all imports and exports just by reading the source code — without executing it first.
- Scoped by default — each module has its own scope (no globals unless you make them).
- Works natively in modern browsers and Node.js (v12+) with "type": "module" in package.json.
Simple Example
Using ES Modules allows you to write your code in a more structured and modular way. In this example, we’ll create a simple counter by splitting the code across multiple JavaScript files instead of keeping everything in one.
This is folder structure.
my-app/
│
├── index.html
├── js/
│ ├── main.js
│ ├── components/
│ │ ├── Counter.js
│ │ └── Button.js
│ └── utils/
│ └── dom.js
└── styles.css
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ESM Components Example</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1>ESM Counter Example</h1>
<div id="app"></div>
<!-- Load entry point as module -->
<script type="module" src="./js/main.js"></script>
</body>
</html>
js/utils/dom.js
A simple DOM helper:
// js/utils/dom.js
export function createElement(tag, options = {}) {
const el = document.createElement(tag);
if (options.className) el.className = options.className;
if (options.text) el.textContent = options.text;
if (options.onClick) el.addEventListener('click', options.onClick);
return el;
}
- Defines a utility function called createElement() in JavaScript that helps you create and configure DOM elements more conveniently.
js/components/Button.js
This component just creates a button element.
// js/components/Button.js
import { createElement } from '../utils/dom.js';
export function Button(label, onClick) {
return createElement('button', {
className: 'btn',
text: label,
onClick
});
}
js/components/Counter.js
A component that uses internal state (via closure):
// js/components/Counter.js
import { Button } from './Button.js';
import { createElement } from '../utils/dom.js';
export function Counter() {
let count = 0;
const container = createElement('div', { className: 'counter' });
const display = createElement('p', { text: `Count: ${count}` });
const incButton = Button('+', () => {
count++;
display.textContent = `Count: ${count}`;
});
const decButton = Button('-', () => {
count--;
display.textContent = `Count: ${count}`;
});
container.append(display, incButton, decButton);
return container;
}
Counterreturns a DOM element.- It has its own internal state (count) — encapsulated.
- Declares a local variable count initialized to 0.
- This variable will live as long as the component exists (a closure keeps it alive inside event handlers).
- A closure is when a function “remembers” the variables from the scope where it was created, even after that scope has finished running.
- The arrow functions for the + and - buttons close over count and display, letting them update the same count value each time you click — even though Counter() has already returned.
- It reuses the Button component.
js/main.js
Entry point, where everything comes together.
// js/main.js
import { Counter } from './components/Counter.js';
const app = document.getElementById('app');
app.append(Counter());
styles.css
body {
font-family: sans-serif;
text-align: center;
margin-top: 3rem;
}
.counter {
display: inline-flex;
align-items: center;
gap: 1rem;
}
.btn {
font-size: 1.5rem;
padding: 0.5rem 1rem;
}
Run
Start a simple local server:
npx serve .
AI-generated Content Disclaimer
Some portions of this text were created with the assistance of AI language models. While effort has been made to ensure accuracy, the content may contain errors or incomplete information. Please use your own judgment and verify details when necessary.
