Node.js takes the JavaScript engine out of the browser and gives it abilities a browser deliberately does not have: reading and writing files, listening on network ports, and talking to the operating system. That makes it a good home for your back end. This lesson tours the few built-in parts you will meet in the rest of the course, so none of them feels strange later.
Built-in modules
Node.js comes with modules that you import by name with the node: prefix: node:fs (files), node:path (paths), node:os (information about the computer), node:http (network servers), node:events and node:crypto. The prefix tells readers and tools that this is a built-in, not a package from npm.
Files and paths
fs/promises gives you promise versions of the file functions, so you can await them: readFile, writeFile, rm, mkdir. Always build paths with path.join(...) instead of gluing strings with slashes, because Windows uses backslashes and macOS and Linux use forward slashes; path.join does the right thing on both. In ES modules there is no __dirname, so you create it from import.meta.url as the example does. You will do exactly this in lesson 36 when the server stores uploaded resumes.
Events
EventEmitter lets one part of a program announce that something happened (emit) and other parts react (on). It is the idea behind many Node.js objects: servers emit request, streams emit data, Mongoose connections emit disconnected. You will use res.on('finish', ...) in the request logger in lesson 10.
process: the running program
process.env holds environment variables: settings that come from outside your code, such as the port number or a database address. process.argv holds the command line words, process.platform the operating system, and process.uptime() how long the program has run. Environment variables are how you keep secrets and per-computer settings out of your source code, which is a rule you set in lesson 6.
// Lesson 7: Node.js building blocks. Run: node examples/07-node/modules-and-files.js
import fs from 'node:fs/promises';
import path from 'node:path';
import os from 'node:os';
import { EventEmitter } from 'node:events';
import { fileURLToPath } from 'node:url';
// path: build file paths that work on Windows, macOS and Linux
const here = path.dirname(fileURLToPath(import.meta.url));
const file = path.join(os.tmpdir(), 'job-tracker-demo.json');
console.log('this file lives in', path.basename(here));
// fs: read and write files (promise version, so we can await it)
await fs.writeFile(file, JSON.stringify([{ company: 'Acme', role: 'Clerk' }], null, 2));
const jobs = JSON.parse(await fs.readFile(file, 'utf8'));
console.log('read back:', jobs);
await fs.rm(file);
// events: one part of a program announces something, another part reacts
const bus = new EventEmitter();
bus.on('job:added', (job) => console.log('send a confirmation for', job.company));
bus.emit('job:added', { company: 'Northwind' });
// process: information about the running program
console.log('Node', process.version, 'on', process.platform);
console.log('PORT from the environment:', process.env.PORT ?? '(not set)');
console.log('arguments you passed:', process.argv.slice(2));
Run it with node examples/07-node/modules-and-files.js hello world. You will see the extra words in process.argv. Now run it with a variable set: on macOS and Linux PORT=8080 node examples/07-node/modules-and-files.js, on Windows PowerShell $env:PORT=8080; node examples/07-node/modules-and-files.js. The printed port changes without any change to the code. That is the whole point of configuration by environment.
Your task
- Run the example, then run it again with extra words and with
PORTset. - Write a script
count-jobs.jsthat reads a JSON file of jobs, prints how many there are for each status, and writes the result toreport.json. - Make an
EventEmitterthat announcesjob:addedand attach two listeners. Check that both run.
How to check it worked
process.env.PORTshows your value when set and(not set)when not.- Your script writes a valid
report.json.
Summary
- Built-in modules (
node:fs,node:path,node:http) give Node.js access to files, paths and the network. - Use
path.joinfor paths; read settings fromprocess.env. - Events let parts of a program react to each other.