Back to Tsx

Node.js internals notes

notes/node/README.md

4.23.14.7 KB
Original Source

Node.js internals notes

Maintainer notes tracking how Node module-loading internals affect tsx. These are not user docs (files: ["dist"] keeps them out of the npm package).

tsx fills gaps in Node's TypeScript and module-loading story. As Node adds native support — type stripping, require(esm), sync module hooks — those gaps get smaller, which is the preferred direction. These notes keep tsx aligned with Node behavior and identify the remaining gaps where tsx still helps users today.

Reading order

Mechanism stories

FileCovers
module-hooks.mdAsync module.register() vs sync module.registerHooks(), loader-worker cost, CJS-reload safety
cjs-loader.mdCJS resolution, cache identity, require.extensions, eager ESM error decoration
cjs-esm-interop.mdESM importing CJS, CJS requiring ESM, named-export preparsing, module.exports interop
type-stripping.mdNode's native TypeScript pipeline, limitations, current issues, tsconfig contract

Reference maps

FileCovers
gate-reference.mdSmaller gates: import attributes, import.meta props, wasm, package main, test runner flags
node-integration-points.mdNode loader integration points to re-verify across releases

Gate index

src/utils/node-features.ts gateContext
moduleRegistermodule-hooks.md
moduleRegisterHooksCjsReloadmodule-hooks.md
importAttributesgate-reference.md
testRunnerGlobgate-reference.md
cliTestFlaggate-reference.md
esmLoadReadFilecjs-esm-interop.md
importMetaPathPropertiesgate-reference.md
requireEsmcjs-esm-interop.md
requireEsmNoWarningcjs-esm-interop.md
cjsNamespaceModuleExportscjs-esm-interop.md
nativeTypeScripttype-stripping.md
wasmModulesgate-reference.md
cjsNamespaceFromLoadHookcjs-esm-interop.md
requireEsmExtensionlessMjscjs-esm-interop.md
modulePackageMainResolutiongate-reference.md

Entry format

Each documented behavior should record:

  1. what changed in Node;
  2. the Node PR or issue;
  3. verified versions — first release per major line, confirmed from Node git history;
  4. exact tagged Node source anchors (github.com/nodejs/node/blob/<tag>/...#L...), ideally last-without and first-with for boundaries;
  5. tsx code paths affected;
  6. coverage when relevant.

Optional sections:

  • ## Decisions for untestable tradeoffs and rejected alternatives;
  • ## Implementation history in tsx for old commits/PRs that explain why the current approach exists.

Testable behavior belongs in tests/; these notes explain context and maintenance intent.

Verification workflow

Version boundaries are pinned from Node's git history, because backports often land after the main-line commit.

text
cd /path/to/nodejs/node
git fetch --tags

# Every commit carrying a PR-URL trailer = main-line commit + all backport
# cherry-picks. Collect all release tags containing them, first per major line:
pr=59929
{ for sha in $(git log --grep "PR-URL: https://github.com/nodejs/node/pull/${pr}\$" --format=%H --all); do
    git tag --contains "$sha" | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$'
  done; } | sort -u -V | awk -F. '{maj=$1} maj!=prev{print; prev=maj}'

After finding the boundary, verify the exact source shape with git show <tag>:<path> and link the public GitHub URL. Do not link to moving branches for source claims.

Verification caveats:

  • A PR can be the fix to a feature, not its introduction. When PR-contains and source-reading disagree, read the source at the tag and document both.
  • A fix backported only to an older line means newer lines may never have had the bug; model that as a range or a line-specific gate.
  • Some gates describe a bug window [from, before) — opened by one PR, closed by another.