JavaScript Module Systems
ESM vs CommonJS, the incompatibility that causes constant production issues, dual packages, import maps, and the module resolution algorithms used by Node and bundlers.
How Node.js actually loads modules — the synchronous require() algorithm, the module wrapper function, the cache that prevents re-execution, and why circular dependencies don't crash your app.
How ES modules actually work — static imports, live bindings (not copies), import hoisting, strict mode by default, top-level await, dynamic import(), and import.meta.
Why ES modules and CommonJS don't mix easily — synchronous vs asynchronous, live bindings vs value copies, the dual module hazard, and the practical workarounds every Node.js developer needs.
Master the package.json exports field — conditional exports, subpath patterns, the type field, .mjs/.cjs extensions, and how to ship a package that works for every consumer.
How browsers load ES modules natively — script type=module, import maps for bare specifiers, modulepreload for performance, and when you still need a bundler.
How Node.js finds your modules — the CJS resolution algorithm, ESM resolution, node_modules lookup, the exports field, TypeScript module resolution modes, and path mapping.
How tree shaking actually works — why it requires ESM, what the sideEffects field does, the common killers (barrel files, re-exports, CJS), and how to measure if your code is tree-shakeable.
10 progressively harder challenges testing your mental model of CJS vs ESM exports, live bindings, circular dependencies, tree shaking, the exports field, and module resolution.