Explore advanced ES Modules features including dynamic imports, top-level await, live bindings, and handling circular dependencies.
Use the import()
function to lazy-load modules on demand for code splitting and improved performance.
// Load module dynamically
const module = await import('./heavy-module.js');
module.doSomething();
// Conditional loading
if (userIsAdmin) {
const adminFeature = await import('./admin-panel.js');
adminFeature.init();
}
// Dynamic path (use with caution)
const lang = 'en';
const translations = await import(`./i18n/${lang}.js`);
Benefits:
Use await
outside of an async function at the top level of a module.
// Fetch config before app loads
const config = await fetch('/api/config').then(r => r.json());
// Load database connection
import { connectDB } from './database.js';
const db = await connectDB();
export { config, db };
⚠️ Important:
Top-level await blocks module loading. Modules that import this module will wait until the await completes.
Imports are live, read-only views into exported variables. Changes in the exporting module are reflected in importing modules.
// counter.js
export let count = 0;
export function increment() { count++; }
// main.js
import { count, increment } from './counter.js';
console.log(count); // 0
increment();
console.log(count); // 1 (live binding!)
// count = 10; // ❌ Error: Assignment to constant variable
// Imports are read-only!
ES Modules' live bindings can handle some circular dependency cases gracefully, unlike CommonJS.
// a.js
import { b } from './b.js';
export const a = 'a';
console.log('a.js:', b); // Works!
// b.js
import { a } from './a.js';
export const b = 'b';
console.log('b.js:', a); // May be undefined during init
// main.js
import './a.js'; // Resolves circular dependency
✅ Best Practice:
Avoid circular dependencies when possible. Refactor shared code into a third module.
import.meta
provides metadata about the current module.
// Get module URL
console.log(import.meta.url);
// file:///path/to/module.js or https://example.com/module.js
// Load assets relative to module
const imagePath = new URL('./image.png', import.meta.url);
// In Vite/Webpack - environment variables
console.log(import.meta.env.VITE_API_KEY);
See advanced ES Module features in action - dynamic imports and top-level await executing live. Click "Edit in CodePen" to experiment!