Load page modules on-demand as users navigate:
// router.js
export class Router {
constructor() {
this.routes = new Map();
}
register(path, loader) {
this.routes.set(path, loader);
}
async navigate(path) {
const loader = this.routes.get(path);
if (loader) {
const module = await loader();
return module.default;
}
throw new Error(`Route not found: ${path}`);
}
}
// app.js
import { Router } from './router.js';
const router = new Router();
router.register('/', () => import('./pages/home.js'));
router.register('/about', () => import('./pages/about.js'));
router.register('/contact', () => import('./pages/contact.js'));
// Navigate
const page = await router.navigate(window.location.pathname);
page.render();
Reusable API client as a singleton:
// api-client.js
export class APIClient {
constructor(baseURL) {
this.baseURL = baseURL;
}
async get(endpoint) {
const response = await fetch(`${this.baseURL}${endpoint}`);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json();
}
async post(endpoint, data) {
const response = await fetch(`${this.baseURL}${endpoint}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json();
}
}
// Create singleton instance
export const api = new APIClient('https://api.example.com');
// Usage in other files
import { api } from './api-client.js';
const users = await api.get('/users');
const newUser = await api.post('/users', { name: 'John' });
Conditionally load features based on flags:
// config.js
export const features = {
darkMode: true,
analytics: false,
betaFeatures: true
};
// app.js
import { features } from './config.js';
// Load features conditionally
if (features.darkMode) {
const { enableDarkMode } = await import('./dark-mode.js');
enableDarkMode();
}
if (features.analytics) {
const { initAnalytics } = await import('./analytics.js');
initAnalytics();
}
if (features.betaFeatures) {
const { loadBetaFeatures } = await import('./beta.js');
loadBetaFeatures();
}
Simple reactive state management:
// store.js
class Store {
constructor(initialState = {}) {
this.state = initialState;
this.listeners = new Set();
}
getState() {
return this.state;
}
setState(updates) {
this.state = { ...this.state, ...updates };
this.notify();
}
subscribe(listener) {
this.listeners.add(listener);
return () => this.listeners.delete(listener);
}
notify() {
this.listeners.forEach(listener => listener(this.state));
}
}
export const store = new Store({ count: 0, user: null });
// component.js
import { store } from './store.js';
store.subscribe(state => {
console.log('State updated:', state);
});
store.setState({ count: 1 });
Extensible plugin architecture:
// plugin-manager.js
const plugins = [];
export function registerPlugin(plugin) {
if (plugin.name && plugin.init) {
plugins.push(plugin);
console.log(`Plugin registered: ${plugin.name}`);
}
}
export async function initializePlugins() {
for (const plugin of plugins) {
await plugin.init();
}
}
export function getPlugins() {
return plugins;
}
// plugins/logger.js
import { registerPlugin } from '../plugin-manager.js';
registerPlugin({
name: 'logger',
init() {
console.log('Logger plugin initialized');
}
});
// plugins/auth.js
import { registerPlugin } from '../plugin-manager.js';
registerPlugin({
name: 'auth',
async init() {
console.log('Auth plugin initialized');
}
});
// main.js
import './plugins/logger.js';
import './plugins/auth.js';
import { initializePlugins } from './plugin-manager.js';
await initializePlugins();
Watch all 6 ES Module patterns execute live in your browser. See real imports, exports, and execution flow. Click "Edit in CodePen" to modify and experiment!
Build reusable custom elements using ES Module patterns:
// components/user-card.js
import { html, css } from './template-utils.js';
class UserCard extends HTMLElement {
static get observedAttributes() {
return ['name', 'role'];
}
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
this.render();
}
render() {
const name = this.getAttribute('name') || 'Unknown';
const role = this.getAttribute('role') || 'User';
this.shadowRoot.innerHTML = `
<style>
:host { display: block; padding: 1rem; }
.card { border: 1px solid #ccc; border-radius: 8px; padding: 1rem; }
</style>
<div class="card">
<h3>${name}</h3>
<p>${role}</p>
</div>
`;
}
}
customElements.define('user-card', UserCard);
// Usage in HTML:
// <script type="module" src="./components/user-card.js"></script>
// <user-card name="Alice" role="Developer"></user-card>
Use ES Modules in Web Workers for off-main-thread computation:
// worker.js - ES Module worker
import { processData } from './data-processor.js';
self.onmessage = async (event) => {
const result = await processData(event.data);
self.postMessage(result);
};
// main.js - create module worker
const worker = new Worker('./worker.js', {
type: 'module' // Enable ES Module support
});
worker.postMessage({ items: largeDataset });
worker.onmessage = (event) => {
console.log('Processed:', event.data);
};
Browser Support:
Module Workers are supported in Chrome 80+, Safari 15+, and Edge 80+. Firefox support is in progress.