JS

Modules

JavaScript · 8 entries

Named Exports

syntax
export const name = value;
export function fn() { ... }
export { a, b, c };
example
// mathUtils.js
export const PI = 3.14159;

export function areaOfCircle(radius) {
  return PI * radius ** 2;
}

export function circumference(radius) {
  return 2 * PI * radius;
}

Note Named exports can be many per module. They must be imported by exact name (or renamed with 'as'). Prefer named exports for better tree-shaking.

Named Imports

syntax
import { name1, name2 } from "./module.js";
import { name as alias } from "./module.js";
example
import { areaOfCircle, circumference as circ } from "./mathUtils.js";

console.log(areaOfCircle(10));
console.log(circ(10));

Note Imports are live bindings -- they reflect the current value in the exporting module. They are also read-only; you cannot reassign an imported binding.

Default Export and Import

syntax
export default expression;
import anyName from "./module.js";
example
// logger.js
export default class Logger {
  constructor(prefix) {
    this.prefix = prefix;
  }
  log(msg) {
    console.log(`[${this.prefix}] ${msg}`);
  }
}

// app.js
import Logger from "./logger.js";
const log = new Logger("App");
log.log("Started");
output
[App] Started

Note Only one default export per module. Can be imported with any name. You can combine default and named imports: import Logger, { version } from "./logger.js".

Dynamic Import

syntax
const module = await import("./module.js");
example
async function loadEditor() {
  const { EditorView } = await import("./editor.js");
  return new EditorView(document.getElementById("editor"));
}

// Conditional loading
if (needsCharting) {
  const { renderChart } = await import("./charts.js");
  renderChart(data);
}

Note Returns a promise that resolves to the module namespace. Ideal for code-splitting, lazy loading, and conditional imports. Works at runtime, not just at the top of a file.

Re-exporting

syntax
export { name } from "./module.js";
export { default } from "./module.js";
export * from "./module.js";
example
// components/index.js (barrel file)
export { Button } from "./Button.js";
export { Modal } from "./Modal.js";
export { Tooltip } from "./Tooltip.js";

// Consumer
import { Button, Modal } from "./components/index.js";

Note Barrel files simplify imports but can hurt tree-shaking if not handled carefully. Modern bundlers mitigate this, but be aware of the tradeoff.

import.meta

syntax
import.meta.url
import.meta.resolve(specifier)
example
// Get the URL of the current module
console.log(import.meta.url);
// "file:///project/src/utils.js"

// Resolve a relative path
const configPath = new URL("./config.json", import.meta.url);
console.log(configPath.href);

Note import.meta provides module-specific metadata. In Node.js, use import.meta.dirname and import.meta.filename (Node 21+) as replacements for __dirname and __filename.

Namespace Import

syntax
import * as name from "./module.js";
example
import * as validators from "./validators.js";

const email = "test@example.com";
console.log(validators.isEmail(email));
console.log(validators.isNotEmpty(email));

Note Imports all named exports as a single object. The object is frozen (read-only). Useful when a module has many exports you want to use together.

Top-Level await

syntax
// In an ES module
const data = await fetchData();
example
// config.js (ES module)
const response = await fetch("/api/config");
export const config = await response.json();

// app.js
import { config } from "./config.js";
console.log(config.appName); // Available immediately

Note Only works in ES modules (not CommonJS). Importing modules that use top-level await will block until that await resolves, so use judiciously.