NodeJS by Example: ES Modules
|
ES Modules (ESM) are the official JavaScript module system. Node.js fully supports ESM, providing modern import/export syntax. |
|
|
Basic Imports Import from Node.js built-in modules using node: prefix. |
|
|
Named Exports Export multiple values from a module. In math.js: export const PI = 3.14159; export function add(a, b) { return a + b; } export function multiply(a, b) { return a * b; } Import named exports import { PI, add, multiply } from './math.js'; |
|
|
Default Exports Export a single main value from a module. In logger.js: export default class Logger { log(msg) { console.log(msg); } } Import default export import Logger from './logger.js'; |
|
|
Mixed Exports Combine default and named exports. In utils.js: export default function main() {} export const helper1 = () => {}; export const helper2 = () => {}; Import both import main, { helper1, helper2 } from './utils.js'; |
|
|
Renaming Imports Use 'as' to rename imports and avoid conflicts. import { helper as utilHelper } from './utils.js'; |
|
|
Namespace Imports Import all exports as a single object. import * as utils from './utils.js'; |
|
|
Re-exporting Export from another module. In index.js (barrel file): export { add, multiply } from './math.js'; export { default as Logger } from './logger.js'; export * from './utils.js'; |
|
|
Dynamic Imports Import modules at runtime with import(). Conditional loading |
|
|
import.meta Access module metadata. Convert URL to path |
|
|
import.meta.resolve() Resolve module specifiers to URLs. Resolve relative paths const localModule = import.meta.resolve('./local.js'); |
|
|
Top-Level Await Use await at the module's top level. Fetch config at startup const config = await readFile('./config.json', 'utf8') .then(JSON.parse) .catch(() => ({})); Wait for async initialization await database.connect(); |
|
|
JSON Imports Import JSON files with import assertions. import pkg from './package.json' with { type: 'json' }; console.log('Package name:', pkg.name); |
|
|
Conditional Exports (package.json) Define different entry points for different conditions. |
|
|
Subpath Exports Export specific subpaths from a package. Usage: import { feature } from 'my-package/feature'; |
|
|
Module Resolution How Node.js finds modules. 1. Built-in modules: node:fs, node:path 2. Absolute paths: /home/user/module.js 3. Relative paths: ./module.js, ../module.js 4. Package names: lodash, express |
|
|
ESM vs CommonJS Differences Key differences to be aware of. ESM: - Static imports (hoisted, analyzed at parse time) - this is undefined at top level - No __filename, __dirname (use import.meta) - import/export syntax - .js extension required for relative imports CommonJS: - Dynamic requires (can be conditional) - this refers to module.exports - __filename, __dirname available - require/module.exports syntax - Extension optional |
|
|
Interoperability with CommonJS Import CommonJS modules from ESM. CJS module exports: module.exports = { hello: 'world' }; module.exports = function() {}; Import in ESM: import pkg from 'cjs-package'; // default import import { named } from 'cjs-package'; // may work if CJS exports object |
|
|
Creating Dual Packages (ESM + CJS) Support both module systems. |
|
|
Practical Example: Module Factory Create configurable module exports. Export the factory Or export a configured instance |
|
|
Practical Example: Plugin System Dynamic plugin loading with ESM. Usage: const plugins = await loadPlugins([ './plugins/auth.js', './plugins/logging.js' ]); |
|
|
Practical Example: Lazy Loading Load heavy modules only when needed. |
|
|
Best Practices 1. Always use .js extension for relative imports 2. Use node: prefix for built-in modules 3. Prefer named exports for better tree-shaking 4. Use barrel files (index.js) to simplify imports 5. Set "type": "module" in package.json for ESM 6. Use dynamic imports for optional/conditional modules 7. Leverage top-level await for async initialization |
|
|
Run the ES Modules examples Run a single ESM file without package.json Check if running in ESM mode package.json settings for ESM: Use .mjs extension for ESM files in CJS projects Use .cjs extension for CJS files in ESM projects |
|