What you'll be able to do
By the end of this page you should be able to split a tiny app into main.js + helpers, use import / export, load with <script type="module">, and know why file:// sometimes fails (use a local server).
Previous post: localStorage, sessionStorage, and cookies.
Who this is for
- People with one giant
<script>block - Beginners who saw
importin tutorials and got CORS errors - Anyone finishing browser fundamentals before async/fetch phases
You can skip this if you already run Vite or similar. Come back when plain HTML needs one extracted helper file.
export and import
utils.js:
export function greet(name) {
return "Hello, " + name;
}
main.js:
import { greet } from "./utils.js";
console.log(greet("Asha"));
Scenario A — shared formatters across pages later.
Scenario B — default export — one main thing per file is common:
export default function init() { /* ... */ }
import init from "./app.js";
type="module" in HTML
<script type="module" src="main.js"></script>
Module scripts are defer by default — DOM parsed first. They run in strict mode. Top-level variables do not become global window properties.
Paths matter
./utils.js is relative to the HTML URL (or the module URL). Wrong path → 404 in Network tab.
Scenario A — simple folder:
index.html
main.js
utils.js
Scenario B — opening file:// — some browsers block module imports. Use a tiny local server (npx serve, VS Code Live Server) when imports fail mysteriously.
Classic script vs module (quick)
classic <script> | type="module" | |
|---|---|---|
| Scope | global unless wrapped | module scope |
| defer | no (unless attr) | yes by default |
| import/export | no | yes |
A tiny practice file
index.html:
<!DOCTYPE html>
<html>
<body>
<p id="out"></p>
<script type="module" src="main.js"></script>
</body>
</html>
main.js:
import { greet } from "./utils.js";
document.getElementById("out").textContent = greet("Learn");
utils.js:
export function greet(name) {
return "Hello, " + name;
}
Serve the folder over http if file:// blocks modules.
Mistakes I see a lot
1. Forgetting .js extension in import path (browser needs it).
2. Missing type="module".
3. Expecting globals from imported files.
4. CORS / file protocol confusion — not “broken JavaScript,” environment issue.
5. Circular imports in tiny demos — split responsibilities.
What to try before the next post
- Extract one function to
utils.js. - Import it from
main.js. - Open DevTools Network if 404.
- Run via local server if needed.
This closes Phase 7 (browser JS). Next: callbacks and timing — why setTimeout logs feel “out of order,” and how callbacks set up promises.
Try this next outside the series
Browser JavaScript stops feeling isolated once you connect it to forms and component-oriented UI work.
- React forms without pain — see modern form handling after you understand the DOM version first
- HTML to JSX Converter — move tiny HTML snippets into React-style markup when you're ready