Skip to content

opentui: support Node.js 26 alongside Bun#1149

Open
simonklee wants to merge 10 commits into
mainfrom
ot-debunification
Open

opentui: support Node.js 26 alongside Bun#1149
simonklee wants to merge 10 commits into
mainfrom
ot-debunification

Conversation

@simonklee
Copy link
Copy Markdown
Member

Bun remains the primary runtime; Node.js 26 is now a validated
second target, requiring --experimental-ffi for native rendering.
The published packages ship runtime-conditioned exports, the core
test suite runs under both lanes through a repo-owned bun:test
compatibility module, and the keymap and Solid packages have
packed-consumer smoke tests under Node.

Runtime-plugin, Solid preload, and Bun-plugin subpaths stay Bun-only for now.

simonklee added 10 commits June 5, 2026 13:58
Node's node:ffi has no usize, and Bun returns usize values as BigInt,
forcing per-call coercion in the binding layer. Empty Uint8Arrays
also cross to Zig as null pointers, which the old non-optional slice
parameters could not safely accept. Replace usize length arguments
with u32 and make slice pointers optional with explicit zero-length
and null guards. This drops the BigInt round-trips and lines up the
ABI for the Node.
Switch native log and event callback length parameters from usize to
u32 so the JS bridge receives plain numbers on both Bun and Node FFI
backends and avoids per-call BigInt conversion. Arena byte counts
move to u64 and route through a safe-integer guard since the value
can legitimately exceed u32.

Pointer-typed arguments (Pointer, ArrayBuffer, ArrayBufferView, null)
now normalize at the Node symbol boundary, and toArrayBuffer offsets
are validated up front. Callers no longer need to wrap every buffer
in ptr() to satisfy Node's stricter FFI surface.
Decouple the tree-sitter worker from runtime-specific globals so it can
construct and communicate on Node, Bun, and other Worker-capable hosts
through a single seam. The platform layer now owns main-thread worker
construction (including a node:worker_threads shim) and worker-side
message bridging, with a shared typed protocol on both ends.
Allow examples to run under Node 26 with --experimental-ffi in addition to
Bun. Replace some Bun-specific APIs with standard Node equivalents, lazy-load
demos that still require Bun (WebGPU, sprites, shaders), and import Rapier via
its ESM subpath.
Add conditional exports (bun/node/default) so each runtime resolves
the correct variant, and add a packed dist smoke test that verifies
imports work in both Node.js and Bun.
The test suite was tightly coupled to Bun-specific APIs (bun:test,
Bun.sleep) making it impossible to validate behavior on other
runtimes. A module hook now rewrites bun:test imports for Node's
test runner, and fake clocks replace wall-clock delays so tests
run deterministically everywhere.

Fix FFI type mismatches and boolean normalization that caused
silent failures on non-Bun runtimes. Correct bundled asset
resolution so published packages load without a TypeScript loader.

Reorganize the example menu with themed sections, two-panel focus
management, and proper tree-sitter cleanup to prevent worker leaks.
Add jsx/jsxs/jsxDEV/Fragment runtime implementations, split the
build into Node and Bun entry points, and gate CI on Bun tests,
Node source tests, and a packed-consumer smoke test that verifies
the tarball installs and runs under Node.
Pack the dist artifacts, install them into a fresh Node project, and
import every public entrypoint to verify the published shape. Wire the
script into the keymap CI workflow and both npm release jobs so packed
consumers are validated before npm sees them.

Clarify the runtime split in the docs: import-only use is Node-safe,
while creating a native renderer still requires Node 26 with
--experimental-ffi.
Node.js 26.3 expects FFI signatures to use the current argument and return
field names.
Require callers and CI jobs to select the supported Node.js version
instead of downloading a private copy on demand.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant