← Back to Chapters

JavaScript Modules: Import & Export

? JavaScript Modules: Import & Export

? Quick Overview

JavaScript ES modules let you split your code into multiple files. Each file (module) can export values (variables, functions, classes, objects) and other files can import them. This improves reusability, maintainability, and keeps your codebase organised.

To use ES modules in the browser you typically write:

? View Code Example (enable modules in the browser)
<script type="module" src="app.js"></script>

Now app.js can import and export values using the import and export keywords.

? Key Concepts

  • Module: A separate JavaScript file with its own scope.
  • Named export: Exporting one or more values by name from a module.
  • Default export: A single “main” value that a module exports.
  • Namespace import: Import everything from a module into one object.
  • Side-effect import: Import a module just to run its code (no bindings).
  • Dynamic import: Load a module at runtime using import().
  • Import maps: Help the browser resolve bare specifiers (like libraries) to URLs.

? Syntax & Theory

? Exports

  • export const name = value;
  • export function fn() { ... }
  • export default value;

? Imports

  • import { name } from "./file.js";
  • import defaultName from "./file.js";
  • import * as ns from "./file.js";
  • import "./side-effects.js";

Named exports must use their exported names when importing (or be explicitly renamed). A module can have many named exports but only one default export.

? Code Examples

? Named Exports

Export multiple values from a single file, then import them by their exact names.

? View Code Example (named exports)
// math.js
export const PI = 3.14;
export function add(a, b) {
return a + b;
}
? View Code Example (importing named exports)
// app.js
import { PI, add } from "./math.js";

console.log(PI);
console.log(add(2, 3));

⭐ Default Export

Each module can have one default export, imported with any name you like.

? View Code Example (default export)
// greet.js
export default function greet(name) {
console.log("Hello " + name);
}
? View Code Example (importing default export)
// app.js
import sayHello from "./greet.js";

sayHello("Alice");

? Mixing Default and Named Exports

You can combine one default export with additional named exports from the same file.

? View Code Example (mixed exports)
// utils.js
export default function log(msg) {
console.log("LOG:", msg);
}
export const version = "1.0";
? View Code Example (importing mixed exports)
// app.js
import log, { version } from "./utils.js";

log("App started");
console.log(version);

? Import Variations

? View Code Example (different import styles)
// Import everything as a namespace object
import * as math from "./math.js";
console.log(math.add(2, 3));

// Rename imports using "as"
import { add as sum } from "./math.js";
console.log(sum(4, 5));

// Import for side effects only
import "./polyfills.js";

⚡ Dynamic Import

import() lets you load a module at runtime; it returns a promise that resolves to the module object.

? View Code Example (dynamic import)
async function load() {
const { formatDate } = await import("./dateUtils.js");
console.log(formatDate(new Date()));
}

load();

? Import Maps (Browser Only)

Import maps map bare specifiers (like library names) to actual URLs so the browser knows where to load them from.

? View Code Example (import map)
<script type="importmap">{
  "imports": {
    "lodash": "https://cdn.jsdelivr.net/npm/lodash-es@4.17.21/lodash.js"
  }
}</script>

<script type="module">
import { chunk } from "lodash";

console.log(chunk([1, 2, 3, 4], 2));
</script>

? Live Output & Explanation

In these examples, most output appears in the browser’s JavaScript console:

  • console.log(PI); prints 3.14 from the math.js module.
  • add(2, 3) evaluates to 5, showing how functions are shared across files.
  • sayHello("Alice"); logs Hello Alice, using the default export from greet.js.
  • The log() function prepends "LOG:" to messages, demonstrating a reusable logging utility.
  • The dynamic import example fetches dateUtils.js only when needed, then calls formatDate on a Date object.
  • The import map example loads lodash-es from a CDN and uses its chunk() function.

Always open your browser’s DevTools (usually F12) and check the Console tab to see these logs.

? Tips & Best Practices

  • Use named exports for modules that expose many utilities (e.g., math.js, stringUtils.js).
  • Use a default export for the main function or class of a module (e.g., a main component or service).
  • Keep modules small and focused on a single responsibility.
  • Always include type="module" on script tags that use import/export in the browser.
  • Use correct relative paths like ./module.js or ../folder/module.js.
  • Avoid mixing CommonJS require() with ES import in the same file unless your tooling supports it.
  • Prefer clear file names that match the responsibility of the module (e.g., greet.js, dateUtils.js).

? Try It Yourself

  • Create a module config.js that exports two constants (like API_URL and TIMEOUT) and a default function that logs them. Import all three into app.js.
  • Make a math.js module and experiment with import * as math from "./math.js";. Log the math object to see all its members.
  • Build a small page with a button that, when clicked, uses import() to dynamically load a module (e.g., stats.js) and then calls a function from it.
  • Configure an import map that maps a bare specifier like "utils" to your own module file, then import from "utils" inside a <script type="module">.