Two ways to share code
JavaScript has two major module systems. CommonJS grew up in Node with require and module exports, while ES modules are the standard with import and export. They differ in timing and binding.
- CommonJS loads modules synchronously at require time.
- ES modules are parsed first, then linked, then evaluated.
- Both let files share and reuse code.
Static structure and live bindings
ES module imports and exports are static, fixed at parse time before any code runs. This lets tools analyze the graph and enables tree shaking. CommonJS exports are a plain object resolved at runtime.
- ESM imports are live bindings, so they reflect later changes to the export.
- CommonJS gives a copy of the value at the moment of require.
- ESM is asynchronous and supports top level await.
Mixing the two is awkward, since a CommonJS module sees an ES module only through dynamic import. The static nature of ESM is what makes modern bundlers smart, but it also forbids conditional top level imports.
Key idea
ES modules use static, live bindings resolved before execution, while CommonJS uses dynamic require that copies the export value at call time.