ES modules
Introduction
ES modules (ESM) use import and export; each module is its own file.
- JavaScript modules (developer.mozilla.org)
Exporting
export const x = 1 // named export
export function fn() {} // named export
export { a, b } // named exports
export { x as y } // renamed export
export default function () {} // default export (one per module)
export { x } from './x.js' // re-export named
export * from './x.js' // re-export all named
A module has many named exports but only one default.
See: export (developer.mozilla.org)
Importing
import def from './mod.js' // default export
import { a, b as c } from './mod.js' // named exports
import * as ns from './mod.js' // namespace object
import './setup.js' // side effects only
import def, { a } from './mod.js' // default + named
Static imports are hoisted and must be top-level. Named imports are live bindings, reflecting later changes in the exporting module.
See: import (developer.mozilla.org)
Dynamic imports
const mod = await import('./mod.js')
mod.default // the default export
if (needsChart) {
const { Chart } = await import('./chart.js')
}
import.meta.url // → URL of this module
import() returns a promise, so it works inside conditions. import.meta.url
is the module's own URL.
See: import(), import.meta (developer.mozilla.org)
Browser
Importing
index.html
<script type="module" src="main.js"></script>
Browser modules are deferred by default, and relative specifiers need the file extension.
See: JavaScript modules (developer.mozilla.org)
Import maps
index.html
<script type="importmap">
{ "imports": { "lodash": "/vendor/lodash.js" } }
</script>
Bare specifiers (eg import 'lodash') need an import map.
See: import maps (developer.mozilla.org)
Node.js
Module formats
| Extension | Module system |
|---|---|
.mjs | Always ESM |
.cjs | Always CommonJS |
.js | From "type" in package.json |
.mjs and .cjs set the format by extension; .js follows the nearest
package.json.
See: Node.js: determining module system (nodejs.org)
"type": "module"
package.json
{ "type": "module" }
With "type": "module", .js files load as ES modules. Without it, they
default to CommonJS.
See: Node.js: "type" (nodejs.org)
createRequire()
import { createRequire } from 'node:module'
const require = createRequire(import.meta.url)
const legacy = require('./legacy.cjs')
In ESM use import, not require. createRequire() builds a require() for
CommonJS packages.
A CJS module.exports becomes the default export when imported. Node 22.12+
can require() ESM that avoids top-level await.
See: createRequire() (nodejs.org)
0 Comments for this cheatsheet. Write yours!