Skip to content

feat(runner): support Node 20 via oxc-node TypeScript loader#1388

Open
Simon Ingeson (smonn) wants to merge 1 commit into
mainfrom
wiz-10992-support-node-20
Open

feat(runner): support Node 20 via oxc-node TypeScript loader#1388
Simon Ingeson (smonn) wants to merge 1 commit into
mainfrom
wiz-10992-support-node-20

Conversation

@smonn

@smonn Simon Ingeson (smonn) commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Overview of Changes

Lowers the engines.node floor to >=20.19.0 so the CLI installs in the Node 20 environments. On runtimes without native TypeScript (Node 20, Node 22.15–22.17) flows are loaded through the @oxc-node/core ESM loader, which transpiles and resolves TS at runtime; Bun and Node 22.18+ keep their existing paths.

Testing

Verified end-to-end on a real Node 20.19.0 binary; a new runtime-smoke CI matrix drives the real loader on Node 20/22/24 + Bun.

bun run typecheck
bun run lint
bun run format:check
bun run knip
bun run test
bun run build

Checklist

  • Changes follow the code style of this project
  • Self-review completed
  • Tests added/updated (or not applicable)
  • No breaking changes (or described below)

Note: @qawolf/* platform packages declare engines.node >=22.22.0; installs on Node 20 print non-fatal EBADENGINE warnings but the packages are verified to run on 20.19.

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

This PR lowers the supported Node floor to 20.19.0, adds runtime capability detection and a loader strategy selector, and introduces an async registerFlowLoader path that can use @oxc-node/core/register when native TypeScript support is unavailable. It updates the Node version check to compare full semver tuples, wires the new loader into flow loading, marks @oxc-node/core external in build scripts, and adds CI smoke testing across Node 20/22/24 and Bun. Documentation, release notes, and ignore configs are updated for the new runtime setup.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant loadFlowDefault
  participant registerFlowLoader
  participant selectFlowLoaderStrategy
  participant OxcNodeCore

  loadFlowDefault->>registerFlowLoader: await registerFlowLoader()
  registerFlowLoader->>selectFlowLoaderStrategy: selectFlowLoaderStrategy(caps)
  selectFlowLoaderStrategy-->>registerFlowLoader: strategy
  alt strategy is oxc-transpile
    registerFlowLoader->>OxcNodeCore: import `@oxc-node/core/register`
  else strategy is sync-alias
    registerFlowLoader->>registerFlowLoader: register sync alias hook
  else strategy is unsupported
    registerFlowLoader->>loadFlowDefault: throw Error (Node 20.6+ required)
  end
Loading

Related PRs: None identified from the provided summary.
Suggested labels: node-20, ci, build, dependencies
Suggested reviewers: None specified.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title follows Conventional Commits, uses a valid scope, and clearly describes the Node 20 loader support change.
Description check ✅ Passed The description matches the template with Overview, Testing, and Checklist sections filled in and includes concrete verification steps.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch wiz-10992-support-node-20

Comment @coderabbitai help to get the list of available commands.

@smonn Simon Ingeson (smonn) force-pushed the wiz-10992-support-node-20 branch from 3cfc3f0 to 31cc7f3 Compare July 6, 2026 21:52

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/ci.yml (1)

46-99: 📐 Maintainability & Code Quality | 🔵 Trivial

Consider dropping the Node 20 smoke lane .github/workflows/ci.yml:46-99 still exercises node-20, but Node 20 is EOL and no longer receives security fixes. If the Docker target can move, remove this matrix entry; otherwise document why an EOL runtime must stay in CI.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 46 - 99, The runtime-smoke workflow
still includes the node-20 matrix entry even though Node 20 is EOL. Update the
matrix in the runtime-smoke job to remove the node-20 lane if the Docker target
no longer depends on it, and keep the remaining node-22, node-24, and bun lanes
intact; if you must retain Node 20, add an explicit workflow comment near the
matrix in runtime-smoke explaining why the EOL runtime is still required.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ci.yml:
- Around line 58-66: The CI matrix for the Node 20 job is using a floating major
version instead of the declared minimum supported floor. Update the node-20
entry in the workflow matrix to pin the exact minimum Node 20.x version used in
engines.node, and keep the other matrix entries unchanged so the smoke test
exercises the actual supported floor via the setup-node configuration.

In `@README.md`:
- Line 26: The Node support note in README should be updated because the
statement that Node 20 is in maintenance LTS is outdated. Rewrite the sentence
near the supported Node versions text to reflect that Node 20 is EOL or to
direct readers to the current supported LTS line, keeping the wording aligned
with the project’s actual runtime support.

---

Outside diff comments:
In @.github/workflows/ci.yml:
- Around line 46-99: The runtime-smoke workflow still includes the node-20
matrix entry even though Node 20 is EOL. Update the matrix in the runtime-smoke
job to remove the node-20 lane if the Docker target no longer depends on it, and
keep the remaining node-22, node-24, and bun lanes intact; if you must retain
Node 20, add an explicit workflow comment near the matrix in runtime-smoke
explaining why the EOL runtime is still required.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 35452280-245b-44d2-b1c5-32fd067f1e60

📥 Commits

Reviewing files that changed from the base of the PR and between 4894a64 and 3cfc3f0.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (22)
  • .changeset/support-node-20.md
  • .github/workflows/ci.yml
  • .gitignore
  • .oxlintrc.json
  • CONTRIBUTING.md
  • README.md
  • package.json
  • scripts/build.ts
  • scripts/buildBinary.ts
  • src/domains/doctor/checks/nodeVersion.test.ts
  • src/domains/doctor/checks/nodeVersion.ts
  • src/domains/runner/loadFlowDefault.ts
  • src/oxcNode.d.ts
  • src/shell/resolver/detectRuntimeCapabilities.test.ts
  • src/shell/resolver/detectRuntimeCapabilities.ts
  • src/shell/resolver/registerFlowLoader.test.ts
  • src/shell/resolver/registerFlowLoader.ts
  • src/shell/resolver/selectFlowLoaderStrategy.test.ts
  • src/shell/resolver/selectFlowLoaderStrategy.ts
  • test/node20/greeting.ts
  • test/node20/sample.flow.ts
  • test/node20/smoke.mjs

Comment thread .github/workflows/ci.yml
Comment thread README.md Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/shell/resolver/selectFlowLoaderStrategy.ts`:
- Around line 37-41: The native TypeScript path in selectFlowLoaderStrategy
currently falls back to "none" when hasNativeTypeScript is true but hasSyncHooks
is false, which can leave imports unresolved. Update selectFlowLoaderStrategy to
handle this combination explicitly instead of silently returning "none"—either
preserve the expected aliasing behavior or fail/route to a safer strategy—and
add a test in selectFlowLoaderStrategy.test.ts covering caps.hasNativeTypeScript
with caps.hasSyncHooks disabled.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 482e7739-9e0c-491b-9e3f-2ff37b3cfc7d

📥 Commits

Reviewing files that changed from the base of the PR and between 3cfc3f0 and 31cc7f3.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (23)
  • .changeset/support-node-20.md
  • .github/workflows/ci.yml
  • .gitignore
  • .oxlintrc.json
  • CONTRIBUTING.md
  • README.md
  • knip.config.ts
  • package.json
  • scripts/build.ts
  • scripts/buildBinary.ts
  • src/domains/doctor/checks/nodeVersion.test.ts
  • src/domains/doctor/checks/nodeVersion.ts
  • src/domains/runner/loadFlowDefault.ts
  • src/oxcNode.d.ts
  • src/shell/resolver/detectRuntimeCapabilities.test.ts
  • src/shell/resolver/detectRuntimeCapabilities.ts
  • src/shell/resolver/registerFlowLoader.test.ts
  • src/shell/resolver/registerFlowLoader.ts
  • src/shell/resolver/selectFlowLoaderStrategy.test.ts
  • src/shell/resolver/selectFlowLoaderStrategy.ts
  • test/node20/greeting.ts
  • test/node20/sample.flow.ts
  • test/node20/smoke.mjs

Comment thread src/shell/resolver/selectFlowLoaderStrategy.ts
Lower engines.node to >=20.19.0 (the highest real floor across deps:
@qawolf/emails wants 20.19, @clack/prompts 20.12, module.register 20.6).
On runtimes without native TypeScript (Node 20, Node 22.15-22.17) register
the @oxc-node/core ESM loader to transpile and resolve flow modules; Bun
and Node 22.18+ keep their existing paths. A Node without native TS and
without module.register (< 20.6) fails with a clear unsupported-runtime
error, and a failed oxc-addon load reports an actionable message.

The doctor node-version check compares full major.minor.patch so Node
below the floor fails correctly. @oxc-node/core stays external in both the
npm bundle and the compiled binary (unreachable there).

Add a runtime-smoke CI matrix (Node 20/22/24 + Bun) that boots the
published bundle and drives the real registerFlowLoader against a
TypeScript flow whose sibling import exercises .js->.ts aliasing.

The @qawolf/* platform packages declare engines >=22.22.0 but are verified
to run on Node 20.19; installs on Node 20 print non-fatal EBADENGINE
warnings.
@smonn Simon Ingeson (smonn) force-pushed the wiz-10992-support-node-20 branch from 31cc7f3 to c2e13b2 Compare July 6, 2026 22:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants