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.
The script tag you already know
Section titled “The script tag you already know”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.
The module script tag
Section titled “The module script tag”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
importandexportstatements 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
Module scope
Section titled “Module scope”Without type="module", variables leak into the global scope:
// plain scriptconst total = 0; // window.total — visible everywhereWith type="module":
// moduleconst total = 0; // module-scoped — invisible to other files unless exportedThis 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.
Why this matters for BudgetBuddy
Section titled “Why this matters for BudgetBuddy”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 functionsEach 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.
Modules are loaded from a server
Section titled “Modules are loaded from a server”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:
npx serve .Or use the Live Server extension in VS Code. Both will serve your files over http://localhost.
Exercise
Section titled “Exercise”- Create a folder called
budgetbuddywith anindex.htmlfile. - Add a
<script type="module" src="main.js"></script>tag to the HTML. - Create
main.jswith one line:console.log('Module loaded');. - Serve the folder with a local server and open it in the browser.
- Open DevTools — confirm you see
'Module loaded'in the console. - Try adding a
type="module"script and a plain script that both declareconst 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, andmain.jsas the entry point.