AI InterviewSearch…Search problems, topics, or pages…Ctrl KGet started
Skip to content

09 Modules and Node / Checkpoint

Checkpoint — Modules and Node

24 min · +25 XP · 3 exercises · 12 questions

Exercises0/3
Quiz · 70% to clear12 q

This checkpoint covers CommonJS versus ES modules (loading, caching, copies versus live bindings, module type detection, interop, cycles, dynamic import()), package.json fields, the resolution algorithm, semver ranges and lockfiles, the core modules (path, fs, process, events, url, crypto), Buffer and streams with pipeline and backpressure, and the process surface — arguments, environment, exit codes, signals, child processes and workers.

How it works. Twelve questions and three programs; 70% on the questions and every program accepted clears the module.

Before you start, make sure you can answer:

  • How Node decides whether a .js file is CJS or ESM; why ESM imports need extensions; what a live binding is; what CJS does on a circular require.
  • The three steps of resolving require("x"); ^ versus ~ and what ^0.x means; why npm ci and a committed lockfile.
  • path.join versus resolve; the three fs styles; what emit("error") with no listener does; exitCode versus exit().
  • Why pipeline beats pipe; what backpressure is; why chunk.toString() per chunk breaks on UTF-8.
  • exec versus execFile/spawn; what a SIGTERM handler must do; when to use worker_threads.

The programs are a module-graph loader that reproduces CommonJS load order and detects cycles, a stream pipeline that parses and summarises log lines with a Transform in object mode, and a configuration CLI that merges flags, environment and defaults with the standard precedence.

Common questions

What does CommonJS do on a circular require?

It returns the partially filled exports of the module that is still loading, often an empty object, so the module that asked sees undefined for anything defined later. The failure is silent, which is why the fix is to break the cycle by moving the shared code into a third module.

Why does chunk.toString() break UTF-8 text in a stream?

A chunk boundary can fall in the middle of a multi-byte UTF-8 character, so decoding each chunk separately produces garbage at the seams. Call setEncoding("utf8") on the stream, use a StringDecoder, which buffers partial characters, or collect the buffers and decode once with Buffer.concat.

What must a SIGTERM handler do in Node.js?

Stop accepting new work, finish or fail in-flight work quickly, close connections and flush logs, then call process.exit. Installing the handler replaces Node's default exit, so a handler that forgets to exit can leave the process running until the grace period ends and the orchestrator sends an uncatchable SIGKILL.

Node.js Modules Quiz: npm, Streams and Process Practice Test

Test your Node.js with 12 questions and three programs on CommonJS and ES modules, npm and semver, core modules, streams and backpressure, and processes.

  • Course: JavaScript study plan
  • Module: Modules and Node
  • Kind: Checkpoint — cleared at 70%
  • Reading time: 24 min
  • Runtime: Node 16

Checkpoint — Modules and Node is the checkpoint that closes the Modules and Node module: a graded quiz and whole-program exercises, passed at 70%.

Instructions

This checkpoint covers CommonJS versus ES modules (loading, caching, copies versus live bindings, module type detection, interop, cycles, dynamic import()), package.json fields, the resolution algorithm, semver ranges and lockfiles, the core modules (path, fs, process, events, url, crypto), Buffer and streams with pipeline and backpressure, and the process surface — arguments, environment, exit codes, signals, child processes and workers.

How it works. Twelve questions and three programs; 70% on the questions and every program accepted clears the module.

Before you start, make sure you can answer:

  • How Node decides whether a .js file is CJS or ESM; why ESM imports need extensions; what a live binding is; what CJS does on a circular require.
  • The three steps of resolving require("x"); ^ versus ~ and what ^0.x means; why npm ci and a committed lockfile.
  • path.join versus resolve; the three fs styles; what emit("error") with no listener does; exitCode versus exit().
  • Why pipeline beats pipe; what backpressure is; why chunk.toString() per chunk breaks on UTF-8.
  • exec versus execFile/spawn; what a SIGTERM handler must do; when to use worker_threads.

The programs are a module-graph loader that reproduces CommonJS load order and detects cycles, a stream pipeline that parses and summarises log lines with a Transform in object mode, and a configuration CLI that merges flags, environment and defaults with the standard precedence.

Common questions

What does CommonJS do on a circular require?

It returns the partially filled exports of the module that is still loading, often an empty object, so the module that asked sees undefined for anything defined later. The failure is silent, which is why the fix is to break the cycle by moving the shared code into a third module.

Why does chunk.toString() break UTF-8 text in a stream?

A chunk boundary can fall in the middle of a multi-byte UTF-8 character, so decoding each chunk separately produces garbage at the seams. Call setEncoding("utf8") on the stream, use a StringDecoder, which buffers partial characters, or collect the buffers and decode once with Buffer.concat.

What must a SIGTERM handler do in Node.js?

Stop accepting new work, finish or fail in-flight work quickly, close connections and flush logs, then call process.exit. Installing the handler replaces Node's default exit, so a handler that forgets to exit can leave the process running until the grace period ends and the orchestrator sends an uncatchable SIGKILL.

Exercises

Load a module graph the CommonJS way

Lines module <name>: <dep> <dep>… declare modules and what they require (in order); entry <name> names the entry point. Simulate CommonJS loading from the entry: a module is marked loading, pushed on the stack and recorded in the start order; each dependency is required in turn — a loaded module is a cache hit, a loading one is a cycle recorded as a -> b -> a (the stack from the repeated module, plus it) and returns its partial exports, an undeclared one is recorded as missing; then the module is marked loaded and recorded in the finish order. Print start: …, finish: …, cycles: <"; "-joined or none>, missing: <names or none> unused: <declared modules never loaded, or none>.

Example:

module app: config db routes
module config:
module db: config logger
module logger: config
module routes: db handlers
module handlers: routes
module unused: config
entry app

→

start: app config db logger routes handlers
finish: config logger db handlers routes app
cycles: routes -> handlers -> routes
missing: none unused: unused

A log-summarising stream pipeline

Line 1 is the minimum level; each following line is <ISO time> <LEVEL> <message>. Build a pipeline of Readable.from(lines) → a parsing Transform (readable object mode; a line that does not match ^(\S+)\s+(DEBUG|INFO|WARN|ERROR)\s+(.*)$ is counted as malformed and dropped) → a filtering Transform (keep levels ≥ minimum) → a summarising object-mode Writable that counts per level, per hour (characters 11–12 of the time), and remembers the first ERROR. Print seen=<lines> malformed=<n> kept=<n>, levels: <LEVEL=n in DEBUG,INFO,WARN,ERROR order, or none>, byHour: <HHh=n sorted, or none>, firstError: <time message or none>.

Example: WARN and five log lines including one garbage line →

seen=6 malformed=1 kept=3
levels: WARN=1 ERROR=2
byHour: 10h=1 11h=2
firstError: 2024-01-01T10:16:00Z db timeout

A configuration CLI: flag > env > default

Defaults are { port: 3000, host: "localhost", debug: false, workers: 1 }, read from the environment as APP_PORT, APP_HOST, APP_DEBUG, APP_WORKERS. Line 1 of the input is the argv (possibly blank) — only --key=value, --flag (true) and --no-flag (false) matter; the following lines are KEY=VALUE environment entries. For each key take the flag, else the env value, else the default, coercing to the default's type (integers for numbers; true/1/false/0 for booleans; anything else is a TypeError("<key> must be an integer, got <JSON>")/("<key> must be true/false, got <JSON>")). Validate port 1–65535 and workers ≥ 1. Print config=<JSON> and sources: <key=flag|env|default …> and wouldExitWith=0, or invalid: <messages joined by "; "> and wouldExitWith=1.

Example: --port=8080 --debug then APP_HOST=0.0.0.0, APP_WORKERS=4, APP_PORT=9999 →

config={"port":8080,"host":"0.0.0.0","debug":true,"workers":4}
sources: port=flag host=env debug=flag workers=env
wouldExitWith=0

The flag beats APP_PORT; --workers=0 --port=70000 → invalid: port must be 1-65535, got 70000; workers must be at least 1, got 0.

In this module: Modules and Node

← The process — arguments, environment, exit codes, signals, child processes and workers · Unicode and how JavaScript strings really work →