Technology · JavaScript
JavaScript Modules
Organize JavaScript code with ES6 modules using named exports, default exports, and dynamic imports.
TL;DR
- 01Export functions and variables with named or default export syntax.
- 02Import specific names with curly braces, defaults without them.
- 03Use dynamic import() to load modules on demand at runtime.
Named Exports
- Export multiple items from a single module file.
// math.js export function add(a, b) { return a + b; } export function subtract(a, b) { return a - b; } export const PI = 3.14159; - Import named exports using curly brace syntax.
import { add, subtract, PI } from './math.js'; console.log(add(5, 3)); // 8 - Import all named exports under a namespace alias.
import * as Math from './math.js'; console.log(Math.add(5, 3)); // 8 console.log(Math.PI); // 3.14159 - Export declarations inline or at the bottom of the file.
// Inline export const name = 'Alice'; // Bottom-of-file list const age = 30; export { age }; - Re-export items from another module without importing them locally.
// index.js — barrel file export { add, subtract } from './math.js'; export { formatDate } from './date.js';
Default Export
- Export one main item as the default export per file.
// logger.js export default function log(message) { console.log(`[LOG] ${message}`); } - Import the default export without curly braces.
import log from './logger.js'; log('App started'); // [LOG] App started - Name the default import anything you want locally.
import myLogger from './logger.js'; import printMessage from './logger.js'; // Both refer to the same default export - Export a class as the default export for component-style modules.
// UserService.js export default class UserService { getUser(id) { /* ... */ } } - A module can have only one default export.
// Valid: one default export default function main() { } // Invalid: two defaults // export default function a() { } // export default function b() { }
Mixing Named and Default
- Combine named and default exports in the same module.
// utils.js export default function main() { return 'main result'; } export function helper() { return 'helper result'; } export const VERSION = '1.0'; - Import both the default and named exports in one statement.
import main, { helper, VERSION } from './utils.js'; main(); helper(); console.log(VERSION); - Re-export a default as a named export for barrel files.
export { default as UserService } from './UserService.js'; - Rename named exports during re-export for clarity.
export { add as sum } from './math.js'; - Use barrel files (index.js) to simplify deep import paths.
// Without barrel: import UserService from '../../services/UserService.js'; // With barrel: import { UserService } from '../../services/index.js';
Renaming Imports
- Rename imports with the
askeyword to avoid conflicts.import { add as addition } from './math.js'; addition(5, 3); // 8 - Rename the default import to any local name you prefer.
import logMessage from './logger.js'; // Default import already has no fixed name - Rename when two modules export the same identifier.
import { format as formatDate } from './date.js'; import { format as formatCurrency } from './currency.js'; - Rename exports when re-exporting from a barrel file.
export { createUser as default } from './user.js'; - Use renaming to expose a public API name different from internals.
// Internal: camelCase export { _internalHelper as publicHelper } from './helpers.js';
Module Side Effects
- Import a module purely for its side effects with no bindings.
import './polyfills.js'; // Runs polyfill setup code import './analytics.js'; // Registers analytics listeners - Write side-effect code at the module top level to run on import.
// init.js console.log('Module loaded'); document.addEventListener('DOMContentLoaded', initApp); - Use side-effect imports for CSS in bundler environments.
import './styles/global.css'; import './styles/theme.css'; - Modules are evaluated only once even if imported multiple times.
import './init.js'; // runs once import './init.js'; // cached — does not run again - Use dynamic import() to load modules conditionally at runtime.
async function loadChart() { const { Chart } = await import('./chart.js'); return new Chart(document.getElementById('canvas')); }
Tip: Use named exports for multiple values and reserve default exports for the main thing a module provides — keeps imports predictable.
Warning: Circular imports can cause issues — avoid importing A from B while B imports from A, as one module may receive undefined values.