A file can publish a small interface
An ES module has its own scope. export function totalMinutes(...) makes a function available; import { totalMinutes } from "./totals.js" brings that named export into another module. The braces name exports to import; this is module syntax, not an object being copied. Names must match unless you explicitly rename an import with as.
The relative path starts with ./ for the current directory. Use the .js extension in browser modules. A module runs when it is loaded, so keep reusable modules free of surprise printing or changes to the page. Put startup work in the entry file. Importing a function does not call it.
The multi-file editor below runs main.js. Open totals.js to inspect the exported function, then return to main.js and run it. Its output should be 45 and 0. Break the import name deliberately, read the error, and restore it. This is a real module relationship, not a comment pretending to import a file.
Browser modules normally need an HTTP-served page with a script of type=module. Double-clicking local HTML is unreliable for relative module imports. This course’s editor supplies the environment. Day 7 provides a downloadable project with a small local server and explicit commands. You do not need to install Node to complete these in-page lessons.
Predict and trace
Write the output before running. Follow the values through each call; if your prediction differs, identify the first step that surprised you.
// A reusable function has no printing side effect.
function totalMinutes(records) {
let total = 0;
for (const record of records) {
total += record.minutes;
}
return total;
}
console.log(totalMinutes([{ minutes: 20 }, { minutes: 25 }]));
console.log(totalMinutes([]));Check your prediction
45
0The console example shows the function’s behavior. The file tabs below separate its definition from the calls.
Open the file tabs
Check your prediction
45
0Editing a file tab changes that file; Run starts main.js. An export is part of the module’s public contract, so changing its name requires updating its importers too.
Build it yourself
ES Modules: practise
Write titles(books), the function you would export from a model module. Return an array of titles without printing inside the function. Print its joined result and an empty length.
// Keep model code independent of the DOM.Hint 1: the idea
Map the valid records to their title fields.
Hint 2: a first step
The caller, not titles, should format or print the array.
Show one solution
function titles(books) {
return books.map(book => book.title);
}
console.log(titles([{ title: "Notes" }, { title: "The Web" }]).join(", "));
console.log(titles([]).length);Notes, The Web
0In the file editor, add export before a new titles function in totals.js and import it in main.js. Keep both files free of document access. Explain which file owns startup.
Test a changed requirement
In the file editor, add export before a new titles function in totals.js and import it in main.js. Keep both files free of document access. Explain which file owns startup.
Explain before moving on
What crosses the module boundary? Why should a calculation module not query a form?
Where asynchronous module examples run
This file-tab editor supports this synchronous import example. It does not support top-level await in its entry file. Use the single-program editors and the async main entry point introduced on Day 3 for asynchronous examples. The Day 6 controller walkthrough combines its source functions for that editor, while the downloaded project runs their normal ES modules in Node or the browser. This is a limit of this practice editor, not a rule forbidding top-level await in ES modules.
Going further
Read MDN’s module guide after working through the examples. Use it as a reference when you meet an unfamiliar option; finishing every reference section is not required for this course.
Completion is saved in this browser only. It does not measure mastery.