Modules and npm
Scope: sharing code between files, package.json, and
installing libraries with npm. Builds on
Your First Program.
Exporting and importing (ES modules)
// math.mjs
export function add(a, b) {
return a + b;
}
export const PI = 3.14159;
// main.mjs
import { add, PI } from "./math.mjs";
console.log(add(2, 3), PI);
exportmakes names available;importpulls them in.- Relative imports need the
./prefix and the file extension (./math.mjs, not./math) — a common stumbling block coming from other ecosystems.
A module can also have one default export:
// greeter.mjs
export default function greet(name) {
return `Hello, ${name}!`;
}
// main.mjs
import greet from "./greeter.mjs"; // no braces for default
package.json: your project's ID card
npm init -y
Creates package.json:
{
"name": "my-project",
"version": "1.0.0",
"type": "module",
"dependencies": {}
}
"type": "module" is the magic line: it makes plain .js files
behave as ES modules, so you can stop writing .mjs. (Without
it, .js means CommonJS — the ambiguity from
Your First Program.)
Installing libraries
npm install lodash
This:
- Downloads
lodashintonode_modules/ - Records it in
package.jsonunderdependencies - Records exact versions in
package-lock.json
Then use it:
import _ from "lodash";
console.log(_.chunk([1, 2, 3, 4], 2)); // [[1, 2], [3, 4]]
Rules of the road:
- Never hand-edit
node_modules/— it's a cache, regenerated bynpm install. (And never commit it to git — add it to.gitignore.) - Commit
package-lock.json— it pins exact versions so every install is identical. - Check what you're installing. npm is enormous and minimally curated; typosquatting (malicious packages with near-miss names) is real. Prefer well-known packages with lots of weekly downloads.
npm scripts
{
"scripts": {
"start": "node main.js",
"test": "node --test"
}
}
npm start
npm test
Scripts are how Node projects define their standard commands.
node --test runs the built-in test runner — no library needed
for basic tests.
require() when you meet it
Older code uses CommonJS:
const { add } = require("./math.cjs");
module.exports = { add };
You don't need to write this — but you'll read it in older
libraries, Stack Overflow answers, and Node's own docs history.
require is synchronous and returns the exports object.
Check
- [ ] You can export/import with named and default exports
- [ ] You know what
package.json,node_modules, andpackage-lock.jsonare each for - [ ] You can install a library and name two safety rules
Next: Error Handling.