Journal
Sections
Reading settings
No voice for this language in this browser.
More voices
Code and English terms
Off: the page’s voice reads everything, with no pause between two voices.
No voice for this language in this browser.
More voices
More voices: Microsoft Edge has natural online voices, and Windows (Settings › Time & language › Speech), macOS and Android install others.
Progress
Section titled “Progress”- Node.js 24.21.0 installed on Windows, and in CI on Linux, Windows and macOS with .NET 10 and Java 25
- CI: examples, error snippets, solutions and the C# and Java comparisons compared with their expected output on three OSes
- Lesson 1: Node.js, npm and modules
- Lesson 2: values and types
- Lesson 3: functions, scope, closures and
this - Lesson 4: objects, prototypes and classes
- Lesson 5: arrays, iteration and collections
2026-09-14 — Installing Node.js 24.21.0
Section titled “2026-09-14 — Installing Node.js 24.21.0”- The release index lists 24.21.0, published on 2026-09-07, as the latest LTS release, and 26.8.2 as the latest current release. Node.js 26 becomes LTS on 2026-10-28, according to the schedule.
- My machine already had a global Node.js 24.12.0. I left it alone, downloaded
node-v24.21.0-win-x64.zipinto a folder of its own, checked its SHA-256 againstSHASUMS256.txt, and put that folder first on thePATHof the shells that capture the lessons’ outputs.node -p process.versions.v8prints13.6.233.17-node.53; the bundled npm is 11.19.0. - The PowerShell commands of lesson 1 downloaded, checked and expanded the archive in 22 seconds, in a scratch folder.
winget show OpenJS.NodeJS.LTSoffered 24.19.0, two releases behind nodejs.org.
2026-09-14 — The CI
Section titled “2026-09-14 — The CI”javascript-examples.ymlinstalls Node.js 24.21.0 withactions/setup-node@v7, .NET 10 and Java 25, and runscheck.sh. The first push passed on the three OSes in 1 minute 28 seconds: the 52 outputs captured on Windows are identical on Linux and macOS.- Node.js prints absolute paths in its errors, as a file URL, a Windows path, or even a Windows path with the
\\?\long-path prefix, as in the message aboutpackage.jsonin lesson 1.normalize.mjsmakes them relative to the course folder, removes the stack frames and replaces process IDs. - The C# comparison first printed
1.0 / 0as∞, the infinity symbol of my culture’s number format; it now setsCultureInfo.InvariantCulture, which printsInfinityon every machine. Java printed the guitar emoji as?in the Windows console, so the comparison programs print only ASCII. - The CI also installs
@esbuild/win32-x64@0.25.12as a development dependency on each OS, for lesson 1: npm installs it on Windows and stops withEBADPLATFORMon Linux and macOS.
2026-09-14 — Surprises while writing lessons 1-4
Section titled “2026-09-14 — Surprises while writing lessons 1-4”Node.js’s “Did you mean to import” hint depends on the current folder. An ES module import without its extension fails with ERR_MODULE_NOT_FOUND, and Node.js adds a hint with the right path, but only when the command runs from a folder where that relative path also exists. resolveAsCommonJS creates a CommonJS parent module whose file name is never set (resolve.js, lines 888-895), and for a parent without a file name the CommonJS resolver looks from '.' (loader.js, lines 1021-1028). The code is the same on Node.js’s main branch. I found no issue about it with a search for “Did you mean to import” in nodejs/node. check.sh runs the error snippets from their own folder, and runs this one a second time from the course folder, without the hint.
A duplicate function is an error at the top of a module only. Two function describe declarations in the same ES module are a SyntaxError before anything runs; the same two declarations inside a function body, or at the top of a CommonJS file, are accepted, and the second one wins. I had written the duplicate at the top level of the lesson 3 example to show the silent replacement, and got the error instead.
[1, 2, 3].map(multiply) prints [ 0, 2, 6 ]. I passed multiply to map as a harmless example that functions are values, and map passed the index as the second argument. The example stayed in lesson 3, as the trap it is, next to ['1', '2', '3'].map(parseInt).
npm init -y writes "type": "commonjs". npm 11.19 adds the field explicitly; older templates left it out, which made .js files CommonJS by default all the same.
A .cjs file with import gets advice that doesn’t apply. Node.js prints Warning: Failed to load the ES module … Make sure to set "type": "module" in the nearest package.json file or use the .mjs extension, then the SyntaxError. The "type" field can’t help a .cjs file: its extension wins.
require of an ES module works without a warning. Node.js 24.21.0 loads modern.mjs from from-cjs.cjs silently; the documentation says the feature stopped being experimental in 24.15.0. With a top-level await in the module, require throws ERR_REQUIRE_ASYNC_MODULE, which I checked for the solution of exercise 1.
pnpm doesn’t check the platform of a direct dependency. In a scratch project on Windows, npx pnpm@10 add -D @esbuild/linux-x64@0.25.12 installed the Linux package without a warning (pnpm 10.34.5), where npm refuses it with EBADPLATFORM.
2026-09-14 — What GuitarAlchemist/ga’s front end showed (a826864)
Section titled “2026-09-14 — What GuitarAlchemist/ga’s front end showed (a826864)”I read ReactComponents/ga-react-components and Apps/ga-client at commit a826864, looking for the traps of lessons 1 to 4.
- Two lock files.
Apps/ga-clienthas apackage-lock.jsonand apnpm-lock.yaml; nothing keeps the two resolutions in agreement. - A Windows-only package in
devDependencies.ga-react-components/package.json, line 71 lists@esbuild/win32-x64. The course’s CI shows that npm refuses that exact package on Linux and macOS; the folder only has apnpm-lock.yaml, and pnpm installed a foreign platform package without complaint on my machine, so the project probably installs with pnpm everywhere (to verify on Linux). - A saved state that beats the URL. In
SceneOptions.tsx, the URL parameters are applied beforeObject.assignmerges the preferences saved inlocalStorage, and every toggle saves every key. After the first toggle,?tower,?constellations,?weather,?skyboxand?splatsno longer change anything. The merge also keeps unknown keys and values of the wrong type, and a__proto__key replaces the state object’s prototype. Lesson 4 reproduces the three, and its exercise 3 fixes them. This looks like a bug worth an issue. || 0.5where??is meant.BSPDoomExplorer.tsx, line 4895 would turn a rotation speed of 0 into 0.5. No sample gets a speed of 0 today, so it is latent. Line 5386 works becauseNaNis falsy, not because of the grouping it seems to have.- Event listeners are right. The seven
addEventListenercalls of the two front ends that pass athis.…handler use either a function bound once and stored, or an arrow function stored in a field, and none binds inline; lesson 3 runs the three patterns. - Loose equality only for
null. The TypeScript sources use==and!=only as== nulland!= null; the other matches are GLSL shader code in strings. Their ESLint configurations extendjs.configs.recommended, which doesn’t enableeqeqeq. parseIntwithout a radix, inBSPDoomExplorer.tsx, line 2421 andMusicRoomLoader.ts, lines 209-211. The inputs are decimal digits from a name or a regular expression match, so it is harmless there.
To verify
Section titled “To verify”- The installation commands I haven’t run:
winget install OpenJS.NodeJS.LTS, nvm on Linux, and Homebrew’snode@24on macOS. - Whether
pnpm installofga-react-componentssucceeds on Linux and macOS with@esbuild/win32-x64in its development dependencies.