Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Modules in JavaScript

Modules in JavaScript

~12 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026

We already used import/export to split Account and SavingsAccount into their own files – time to cover the ES module system systematically and structure our project cleanly.

Named exports

src/categories.js
export const DEFAULT_CATEGORIES = ['Rent', 'Groceries', 'Leisure', 'Salary'];

export function isValidCategory(category) {
  return DEFAULT_CATEGORIES.includes(category);
}
// Import individually, by exact name:
import { DEFAULT_CATEGORIES, isValidCategory } from './categories.js';

console.log(isValidCategory('Rent')); // true

Default exports

Each file may have AT MOST ONE default export – typical for a file's "main export", like our Account class:

src/account.js
export default class Account {
  constructor(name, startingBalance) {
    this.name = name;
    this.balance = startingBalance;
  }
}
// Default import: the name at import time is FREELY chosen (no curly braces!)
import Account from './account.js';
// Equally valid: import CheckingAccount from './account.js';

Achtung: In this tutorial and our budget app project, we consistently prefer named exports (like Account in chapter 19) – the import name stays CONSISTENT across the whole project, and editors can track renames more reliably. Default exports are a legitimate, widely used pattern, but this consistency property often makes named exports the more robust choice for larger projects.

Renaming with as

// Rename on export:
export { DEFAULT_CATEGORIES as CATEGORIES };

// Rename on import, e.g. to avoid naming conflicts:
import { DEFAULT_CATEGORIES as AllCategories } from './categories.js';

Importing everything as a namespace

import * as Categories from './categories.js';

console.log(Categories.DEFAULT_CATEGORIES);
console.log(Categories.isValidCategory('Rent'));

Cleanly structuring the budget app project

With modules, let's finally split up our project, which has so far grown in a single index.js:

Project structure after chapter 21

haushaltsbuch-app/
├── package.json
└── src/
    ├── index.js
    ├── account.js
    ├── savingsAccount.js
    └── categories.js
src/index.js
import { Account } from './account.js';
import { SavingsAccount } from './savingsAccount.js';
import { DEFAULT_CATEGORIES, isValidCategory } from './categories.js';

const checking = new Account('Checking', 1500);
checking.record('January salary', 2400, 'Salary');

const savings = new SavingsAccount('Money Market', 5000, 2.5);
savings.creditYearlyInterest();

console.log(checking.formatBalance());
console.log(savings.formatBalance());
console.log('Valid categories:', DEFAULT_CATEGORIES);
console.log(isValidCategory('Car')); // false

ES modules bring two important properties CommonJS (chapter 2) lacks: every file automatically runs in strict mode (relevant to chapter 17's this behavior), and every file has its OWN module scope – top-level variables do NOT automatically "leak" into the global scope, unlike classic <script> tags in a browser.

With that, phase 3 (scope, closures, OOP) is complete! Phase 4 covers asynchrony: iterators, the event loop, promises, and async/await.