Import & Export Patterns
Master the syntax of modular communication. Learn how to design clean public APIs using named exports, default exports, and the high-performance "Live Binding" mechanism.
Named Exports: The Pro Choice
In large-scale engineering, **Named Exports** are generally preferred over defaults. They provide better **static analyzability**, allow IDEs to offer 100% accurate autocomplete, and make grepping for symbols significantly easier. Unlike defaults, named exports force the consumer to use specific identifiers, reducing naming ambiguity across the codebase.
// Engineering Pattern: Named Exports for Discovery
// Named exports are better for tooling and refactoring.
export const API_VERSION = 'v2';
export const fetchUser = (id) => { /* ... */ };
// Aggregated Export
const theme = 'dark';
const toggleTheme = () => { /* ... */ };
export { theme, toggleTheme };The Live Binding Mechanism
A critical differentiator for ES Modules is that they use **Live Bindings**. In older systems like CommonJS, when you exported a value, the importer received a *copy* of that value at that point in time. In ESM, importers receive a **read-only view** into the original memory location of the exporter.
// Technical Insight: Live Bindings vs. Copies
// counter.js
export let count = 0;
export const increment = () => count++;
// app.js
import { count, increment } from './counter.js';
console.log(count); // 0
increment();
console.log(count); // 1
// count = 10; // TypeError: Assignment to constant variable.
// Importers get a read-only live view.Aggregating Exports (Barrels)
As your project grows, you don't want consumers to reach deep into your folder structure (e.g., `import X from '../../internal/utils/helper'`). Instead, you use **Re-exporting** in an `index.js` file to define a "Public API" for a folder. This pattern is often called a **Barrel**.
// Library Pattern: The Barrel File (index.js)
// Centralizing imports to define clear public APIs.
export { login, logout } from './auth.js';
export * from './ui-components.js'; // Re-export all named
export { default as Modal } from './Modal.js'; // Re-export default as namedTechnical Insight: The "Default" Debt
While `export default` is convenient for single-item modules (like React components), it introduces two engineering "debts": 1. **Naming Inconsistency:** Every importer can pick a different name, making the codebase harder to search. 2. **Tree Shaking Latency:** Some older build tools struggle to tree-shake properties off a default-exported object.
Import/Export Checklist:
- ✅ **Explicit:** Favor named exports for utilities and constants.
- ✅ **Bounded:** Use re-exports to hide internal implementation details.
- ✅ **Immutable:** Remember that imported values cannot be reassigned (Read-only).
- ✅ **Lifecycle:** Use side-effect imports (`import './setup.js'`) only for polyfills or global init.
- ✅ **Organization:** Keep imports at the very top of the file for static analysis benefits.