ES Modules
ES Modules
Enabling Modules
<script type="module" src="app.js"></script>
Key Features
- Strict mode by default
- Own scope (no global pollution)
- Asynchronous loading
- Tree-shaking support
Module Scope
// module.js
const private = 'not accessible globally';
export const public = 'accessible';
// app.js
import { public } from './module.js';
console.log(public); // "accessible"
// console.log(private); // Error!
Module vs Script
| Feature | Script | Module |
|---|---|---|
| Scope | Global | Module |
| Strict | Optional | Always |
| Import | N/A | Yes |
| Async | No | Yes |
| defer | Attribute | Default |
Import/Export
Import/Export
Named Exports
// utils.js
export const PI = 3.14159;
export function add(a, b) {
return a + b;
}
export class User {
constructor(name) {
this.name = name;
}
}
// app.js
import { PI, add, User } from './utils.js';
console.log(PI, add(1, 2));
Default Exports
// user.js
export default class User {
constructor(name) {
this.name = name;
}
}
// app.js
import User from './user.js';
Renaming Imports
import { add as sum, PI as pi } from './utils.js';
Importing All
import * as Utils from './utils.js';
console.log(Utils.PI, Utils.add(1, 2));
Side-Effect Imports
import './styles.css';
Dynamic Imports
const module = await import('./module.js');
// In function
async function loadModule() {
const { default: Module } = await import('./module.js');
return new Module();
}
Module Patterns
Module Patterns
Re-Exporting
// index.js - barrel file
export { add, subtract } from './math.js';
export { User } from './user.js';
export { PI } from './constants.js';
// Usage
import { add, User, PI } from './index.js';
Module Organization
src/
modules/
auth/
index.js
login.js
logout.js
user/
index.js
User.js
utils/
index.js
helpers.js
app.js
Namespace Pattern
// constants.js
export const COLORS = {
primary: '#3b82f6',
secondary: '#10b981'
};
export const SIZES = {
small: 12,
medium: 16,
large: 24
};
// Usage
import { COLORS, SIZES } from './constants.js';
Configuration Module
// config.js
const config = {
apiUrl: 'https://api.example.com',
timeout: 5000,
retries: 3
};
export default config;
Circular Dependencies
// Avoid if possible
// a.js
import { b } from './b.js';
export const a = 'a';
// b.js
import { a } from './a.js'; // May fail!
export const b = 'b';
Best Practices
- One module per file
- Use named exports for multiple values
- Use default export for single main value
- Create barrel files for directories
- Avoid circular dependencies
- Import at the top of files
Practice Problems
Create a reusable React component implementing JavaScript Modules. Include proper state management and accessibility.
Solution
// Production-ready component with:
// - Proper TypeScript types
// - Accessibility (ARIA)
// - Error boundaries
// - Loading states
// - Memoization where neededWrite unit and integration tests for JavaScript Modules using React Testing Library.
Solution
// Test coverage:
// 1. Rendering tests
// 2. Interaction tests
// 3. Edge case tests
// 4. Accessibility testsOptimize JavaScript Modules for performance. Consider memoization, code splitting, and bundle size.
Solution
// Optimization techniques:
// 1. React.memo / useMemo / useCallback
// 2. Code splitting with lazy()
// 3. Virtual scrolling for lists
// 4. Image lazy loading
// 5. Bundle analysisQuiz
1. How do you enable ES modules in HTML?
2. What is the difference between named and default exports?
3. How do you import everything from a module?
4. What is a barrel file?
5. What is a dynamic import?
Flashcards
Question
How do you export a value from a module?
Click to reveal answer
Answer
Use export keyword: export const value = 5; export default value;
Question
What is the difference between named and default export?
Click to reveal answer
Answer
Named: export { name }. Default: export default value. Multiple named, one default.
Question
What is a barrel file?
Click to reveal answer
Answer
An index.js that re-exports from a directory: export { name } from './file.js';
Question
What is dynamic import?
Click to reveal answer
Answer
Using import() function to load modules dynamically: const mod = await import('./mod.js');
Question
What are the benefits of ES modules?
Click to reveal answer
Answer
Strict mode, own scope, async loading, tree-shaking, no global pollution.
Revision Notes
Key Takeaways
- 1.ES modules provide native module support
- 2.Named exports allow multiple values per module
- 3.Default export is for the main value
- 4.Barrel files re-export from directories
- 5.Dynamic imports load modules on demand
Interview Tips
- •Know the difference between named and default exports
- •Understand module scope vs global scope
- •Be able to create barrel files
- •Know when to use dynamic imports
Cheat Sheet
ES Modules Cheat Sheet
Exporting
// Named export
export const name = 'John';
export function greet() { }
// Default export
export default class User { }
// Re-export
export { name } from './other.js';
Importing
// Named import
import { name, greet } from './module.js';
// Default import
import User from './module.js';
// Rename
import { name as n } from './module.js';
// All
import * as Module from './module.js';
// Dynamic
const mod = await import('./module.js');
HTML Setup
<script type="module" src="app.js"></script>
Best Practices
- One export per file (default)
- Barrel files for directories
- Avoid circular dependencies
- Import at top of file