ES Modules: import and export
Split code into reusable files with ES modules — named and default exports, import syntax, and dynamic import for lazy loading.
Before modules, scripts shared one global namespace — libraries overwrote each other's variables. ES modules (ESM) give each file its own scope and explicit import/export boundaries. Bundlers (Vite, webpack) and Node resolve file paths into a dependency graph. TypeScript, React, and Next.js all assume you understand import syntax and the difference between default and named exports.
Why modules exist
Modules solve three problems at once: encapsulation (private top-level variables), reuse (import the same util from many files), and dependency structure (tools can tree-shake unused exports). Each module runs once — the first import evaluates the file; later imports get cached exports. That singleton behavior matters for database connections and config loaders.
- File scope — top-level let/const are not global
- Strict mode by default in ES modules
- Static import/export analyzed at build time
- Browsers need type="module" on script tags; Node uses .mjs or "type":"module" in package.json
Named exports — multiple per file
Named exports bind a name you must import with the same name or rename with as. They encourage explicit public APIs — a utils.js file can export formatDate, parseQuery, and clamp without a single default grab-bag. IDEs autocomplete named imports better than default-only modules.
16
5
3.14159
25
3Default export — one primary export
A module may have one default export — often a component, class, or main function. Import name is chosen by the importer (import App from './App'). Default exports are convenient for React pages but can hurt refactoring when every file picks a different name. Many teams prefer named exports for libraries and default only for app entry components.
[LOG] Server startedRe-exports and barrel files
Barrel files (index.js) re-export from submodules so consumers import from a folder path. export { foo } from './foo.js' does not run extra code in the barrel — it forwards bindings. Overusing barrels can hurt tree-shaking and create circular dependency cycles; use them at package boundaries, not for every internal folder.
Dynamic import() — load on demand
import() returns a Promise resolving to the module namespace — use it for code splitting, lazy routes, and loading heavy libraries only when needed. Next.js and React lazy(() => import('./Chart')) rely on this. Static import must be at top level; dynamic import can run inside if blocks and async functions.
Chapter 3 checkpoint
You can model data with arrays and objects, reshape it with destructuring and spread, understand prototype inheritance, and organize files with ES modules — the full vocabulary for reading real npm packages and React codebases. Chat 4 enters async JavaScript: callbacks, promises, async/await, and production error handling.
- 1Arrays: prefer map/filter/reduce over manual loops when transforming
- 2Objects: reference semantics — spread for shallow immutable updates
- 3Destructuring + rest power function APIs and PATCH handlers
- 4class extends prototypes; super calls parent implementation
- 5Next: callbacks, event loop, and promises