Modules and Project Organization
Share one calculation across school reports
Two report screens need the same average rule. Copying the function into both screens risks inconsistent changes, while putting the entire application in one file makes responsibilities harder to find.
A module groups related code and exposes a supported interface. Other modules import that interface rather than duplicating its implementation. Module syntax and loading rules depend on the language and runtime.
Use real files
Write export and import in two runnable JavaScript modules.
Define an interface
Expose a focused marks calculation.
Organize responsibilities
Separate calculation from display and storage.
A report imports the calculation it needs
Calculation module
Export the supported operation.
marks.mjsReport module
Import and call it with student data.
report.mjsReport output
Display the returned result.
37.5
An exported interface is the supported way to use the module
An export makes a value available to importing modules. An import names the value and identifies its module location. In the Node.js example, .mjs marks JavaScript ES-module files and the relative import includes the file extension.
Modules can have private implementation details as well as exports. Keep the public interface focused on callers’ needs. A calculation module should not have to know which page displays its result or where a report will be stored.
Before starting, review one authoritative shared rule. These examples use JavaScript; other languages can use different syntax and rules.
Create two actual ES-module files
JavaScript ES modules · Save these two files together in a new practice folder. The first exports a calculation; the second imports it by a relative file path. With Node.js installed, run node report.mjs in that folder. Expected output is 37.5.
marks.mjs:
export function calculateAverage(maths, science) {
return (maths + science) / 2;
}report.mjs:
import { calculateAverage } from "./marks.mjs";
console.log(calculateAverage(40, 35));Understand the rule inside the exported function
This standalone JavaScript version shows the calculation without module loading, so the lesson can display its checked result. The preceding two-file example is the real import/export implementation.
The rule produces the same value whether called locally or imported. A module boundary organizes access; it does not change arithmetic.
JavaScript · local teaching example
function calculateAverage(maths, science) {
return (maths + science) / 2;
}
console.log(calculateAverage(40, 35));Expected output
37.5Arrange files by responsibilities that can change separately
A small school project might keep marks.mjs for calculations, report.mjs for presenting a report and storage.mjs for reading or saving data. A tests folder can hold checks for the calculations. These are suggested responsibilities, not a compulsory folder count.
Prefer a dependency direction where report code calls calculation and storage operations, while the calculation module does not import report UI code. A circular dependency occurs when modules depend back on one another; initialization order can then become harder to reason about.
Node.js CommonJS uses require and module.exports. Browser ES modules use a script with type="module" and browser loading rules. Use the format established by your project; do not mix import syntax into a CommonJS file without understanding the configuration.
Apply the rule to a small change
Add calculateTotal to the calculation module, then import it in a report. What calculation should the new export contain?
Worked answer
calculateTotal returns maths + science. Export it from marks.mjs and add its name to the import in report.mjs. Calling it with 40 and 35 displays 75; the standalone rule below verifies that calculation.
JavaScript · local teaching example
function calculateTotal(maths, science) {
return maths + science;
}
console.log(calculateTotal(40, 35));Expected output
75Apply the change to both real files
JavaScript ES modules · Replace the two practice files with these versions and run node report.mjs. Expected output is 75. Updating both sides makes the exported name and imported name agree.
marks.mjs:
export function calculateTotal(maths, science) {
return maths + science;
}report.mjs:
import { calculateTotal } from "./marks.mjs";
console.log(calculateTotal(40, 35));Recognize mistakes and limits
Module names, exported names and file paths must agree. A misspelled named import or missing relative file causes a loading error before the calculation can run. Check exact case on systems with case-sensitive file paths.
Do not split files merely to reach a target number of modules. Group code by a coherent responsibility and expose only what callers need. A tiny project may need very few modules.
Importing a module can execute its top-level code. Avoid surprising saves, network requests or other major side effects merely from loading a calculation module; make actions explicit through functions.
For the language or tool rules used here, see Node.js ES-module loading.
Check the core idea
Apply the idea to a new situation
Share a focused interface through real module boundaries
Exports define supported operations and imports let callers use them. Keep file paths and formats correct, group coherent responsibilities and avoid surprising dependencies or import-time actions.
Connect this idea with function interfaces and checking exported rules independently.
See a practical application in organizing a React student-report project, where module boundaries follow responsibilities and components communicate through explicit inputs.
Reaching the recap and completing the quizzes are separate milestones.