Important Differences From Regular Scripts
ES Modules have several key behaviors that distinguish them from ordinary <script> tags.
1. Their Own Scope
Variables declared in one module are NOT visible in others unless explicitly exported. Each module is a private scope.
// counter.js
let count = 0; // only accessible within counter.js
export function increment() { count++; }
export function getCount() { return count; }
2. Code Runs Only Once
No matter how many files import the same module, the module's code executes exactly once on the first import. All importers share the same cached instance.
// logger.js
console.log('Logger module loaded'); // Only logs ONCE, even if imported by 10 files
export function log(msg) { console.log('[LOG]', msg); }
3. import.meta
An object containing metadata about the current module:
console.log(import.meta.url); // Full URL of the current module file
4. Default Exports
Use export default when a module exports one primary thing. On import, you don't need curly braces:
// UserCard.js
export default class UserCard { ... }
// main.js
import UserCard from './UserCard.js'; // No curly braces!
Tip
Use export default for the " main " export of a module (like a React component). Use named exports (export { fn }) for utilities and secondary exports.