Conversation
|
Thanks for taking a stab at this. A few questions, just to start;
|
koffi is a NAPI native module that implements ffi, similar to bun:ffi or this node:ffi pr. Like node:ffi, it passes ArrayBuffer backed values as pointers to native code. They're all quite similar, but bun:ffi is notable for exposing We could make both current version of koffi & any ffi layer based on node:ffi zero-copy by extending the Fun fact, koffi supports and provides premade builds for many architectures / platforms. I only care about the usual linux_x64 / darwin_arm64 / win32_x64 but I think it's cute:
mise is a version manager like
In general think it's good to target the oldest LTS version when building new things unless it's a significant disadvantage to implementation quality. What's the benefit from only targeting the latest version? Probably more importantly, I want to use opentui in a 25 million line codebase that's currently running on Node.js 22 (https://www.notion.com).
No incidental complexity from 3d stuff. Maybe I changed some imports in there to compat/ffi, same as other files. The 3D examples don't run under Node due to deeper dependency on Bun stuff it seems. |
Partially addresses #2
This PR brings Node.js compatibility. Bun-only imports and APIs have been replaced by compatibility interface modules, which pick a runtime-appropriate implementation. Most codepaths when running in
bunare the same as before the PR.Node.js differenes
bun:ffi->@opentui/core/compat/ffi: I re-implemented relevantbun:ffiAPIs on top of koffi. There's more copying than in bun, and I'm unsure about correctness, but I think it's a worthwhile start. The upcoming version of koffi offer capabilities much closer to bun, but I'm not sure when the author will release it.bun:test->@opentui/core/compat/test: I know the AGENTS.md says no vitest, but vitest is the most popular Node.js test runner, and its api is very similar to bun:test. We use vite alias to replace bun:test with the compat module based on vitest. Source code still says"bun:test"because "bun:test" only works when your test file directly imports it.globalThis.Worker->@opentui/core/compat/Worker. Node.js doesn't have a global worker, and its worker_threads worker isn't web-compatible without this shim. Warning: there's a bit of weird node module loader shenanigans here to work around node not understandingimport "./foo.js"meansimport "./foo.ts", but it's pretty benign for opentui's use.bun-ffi-structs: oh boy. I ended up having codex vendor this because module-loader tricks won't work once we're bundled, and it wasn't immediately obvious how to do as a build step. Bun runtime still uses upstream, nodejs gets this hack.Bun.spawnSync->@opentui/core/compat/testHelpers. This is only used in test, so I put in own file to avoid bundling it.Bun.*->opentui/core/compat/runtime: Re-implemented Bun.sleep, Bun.writeFile, and installed the typical npm packages for Bun.stringWidth, Bun.stripANSIimport ... with { ... }->new URL(..., import.meta.url). These were pretty mechanically easy to switch to the more universal option.Testing
Test scripts:
test:bun: the oldbun run test|bun run test:js. Unit tests w/ bun:test.test:nodejs:npx vitest run. Maybe I could usebunxbut I want to run under node!test:dist: New type of integration test that tests that thenpm pack'd artifact actually works in a few very simple example projects. Node is not as forgiving as Bun, so this caught a few goofs that don't show up in vitest or bun test. For example, for some reason Bun@1.2 would emit invalid bundles with duplicate exports, detected by this test. Another case was needing to import react-reconciler/something.js w/ the extension. ¯_(ツ)_/¯ node.Thanks
This is a cool project, and thank you in advance for your attention to this matter.
Let me know if you'd prefer I split up the changes. I personally prefer to review 1 big pr rather than 10 small prs without context, but I know its not the common opinion. Lots of those lines of code are duplicate snapshots!