Skip to content

What Are Modules and Why They Matter

As BudgetBuddy grows, it will have an Expense class, functions for reading and writing localStorage, functions for fetching exchange rates, and functions for updating the DOM. Putting all of that in one file works — until it does not. When you need to find a bug, the file is 500 lines. When you want to reuse a utility function, you cannot — it is buried inside another file. When two developers edit the same file, every merge is a conflict.

Modules are the solution. A module is a JavaScript file that explicitly declares what it exports (shares with other files) and what it imports (uses from other files). Each file has its own scope — no globals, no accidental collisions.

In JavaScript Foundations, you linked JavaScript to HTML with a plain <script> tag:

<script src="main.js"></script>

Every variable declared in main.js becomes a global variable, visible to every other script on the page. That is a problem at scale — one file’s total variable can silently overwrite another file’s total.

To use ES modules, add type="module" to the script tag:

<script type="module" src="main.js"></script>

This single change does several things:

  • The file runs in module scope — its variables are not globals
  • You can use import and export statements inside it
  • The file is deferred automatically — it runs after the HTML is parsed
  • The file is fetched once and cached — multiple imports of the same module do not re-execute it

Without type="module", variables leak into the global scope:

// plain script
const total = 0; // window.total — visible everywhere

With type="module":

// module
const total = 0; // module-scoped — invisible to other files unless exported

This is the behavior you want. Each module manages its own state, and the only way information moves between modules is through explicit import and export.

BudgetBuddy will be split into several focused files:

budgetbuddy/
index.html
main.js ← entry point, imports from other files
expense.js ← Expense class
storage.js ← localStorage read/write functions
api.js ← fetchExchangeRates function
ui.js ← DOM rendering functions

Each file has one job. When you need to fix the Expense class, you open expense.js and nothing else is there to distract you. When you need the exchange rate logic, you open api.js. main.js imports from all of them and wires everything together.

This is how every modern JavaScript project — a React app, an Angular app, a Node.js service — organizes its code.

Because ES modules use the browser’s networking layer to resolve imports, they must be served over HTTP — you cannot open an HTML file directly with file:// and have modules work. Use a local development server.

If you have Node.js installed, the simplest option is:

Terminal window
npx serve .

Or use the Live Server extension in VS Code. Both will serve your files over http://localhost.

  1. Create a folder called budgetbuddy with an index.html file.
  2. Add a <script type="module" src="main.js"></script> tag to the HTML.
  3. Create main.js with one line: console.log('Module loaded');.
  4. Serve the folder with a local server and open it in the browser.
  5. Open DevTools — confirm you see 'Module loaded' in the console.
  6. Try adding a type="module" script and a plain script that both declare const x = 1 — confirm they do not collide.
  • A module is a JavaScript file with its own scope — variables are not global unless exported.
  • Add type="module" to the script tag to opt in to ES module behavior.
  • Module files must be served over HTTP — not opened directly as file://.
  • BudgetBuddy will use one file per concern: expense.js, storage.js, api.js, ui.js, and main.js as the entry point.