[GH-ISSUE #2] Support Node/Deno (NAPI instead of bun:ffi) #3

Open
opened 2026-03-02 23:43:45 +03:00 by kerem · 17 comments
Owner

Originally created by @remorses on GitHub (Jul 29, 2025).
Original GitHub issue: https://github.com/anomalyco/opentui/issues/2

Have you thought about using NAPI to make the project run both in Bun and Node?

There is this package to create automatic NAPI bindings from Zig code https://github.com/cztomsik/napigen

Originally created by @remorses on GitHub (Jul 29, 2025). Original GitHub issue: https://github.com/anomalyco/opentui/issues/2 Have you thought about using NAPI to make the project run both in Bun and Node? There is this package to create automatic NAPI bindings from Zig code https://github.com/cztomsik/napigen
Author
Owner

@kommander commented on GitHub (Jul 29, 2025):

I am open to it. FFI was just really convenient and is faster than NAPI, but yes I gave it some thought already. Might happen at some point, just not priority for now on my side. A lot to be figured out for the actual API and then probably some stabilization needed.

<!-- gh-comment-id:3133559835 --> @kommander commented on GitHub (Jul 29, 2025): I am open to it. FFI was just really convenient and is faster than NAPI, but yes I gave it some thought already. Might happen at some point, just not priority for now on my side. A lot to be figured out for the actual API and then probably some stabilization needed.
Author
Owner

@jlucaso1 commented on GitHub (Jul 29, 2025):

wasm (free standing or wasi) can be considered too?

<!-- gh-comment-id:3133708462 --> @jlucaso1 commented on GitHub (Jul 29, 2025): wasm (free standing or wasi) can be considered too?
Author
Owner

@kommander commented on GitHub (Jul 29, 2025):

@jlucaso1 I considered it in the beginning, but it being a lib for terminal UIs it's not a blocker to load native libs and wasm has some overhead with its vm.

<!-- gh-comment-id:3133888215 --> @kommander commented on GitHub (Jul 29, 2025): @jlucaso1 I considered it in the beginning, but it being a lib for terminal UIs it's not a blocker to load native libs and wasm has some overhead with its vm.
Author
Owner

@esatterwhite commented on GitHub (Nov 12, 2025):

I've only just stumbled onto this project and rather excited by its goals. But, I am confused as to the target run time. Does this only run on bun?

<!-- gh-comment-id:3521738375 --> @esatterwhite commented on GitHub (Nov 12, 2025): I've only just stumbled onto this project and rather excited by its goals. But, I am confused as to the target run time. Does this only run on bun?
Author
Owner

@esatterwhite commented on GitHub (Nov 12, 2025):

Deno also has an FFI interface as well for what its worth.

<!-- gh-comment-id:3521740171 --> @esatterwhite commented on GitHub (Nov 12, 2025): Deno also has an FFI interface as well for what its worth.
Author
Owner

@kommander commented on GitHub (Nov 12, 2025):

It currently only runs on bun exclusively. There are no plans to support other runtimes, though I am open to it.

<!-- gh-comment-id:3521819156 --> @kommander commented on GitHub (Nov 12, 2025): It currently only runs on bun exclusively. There are no plans to support other runtimes, though I am open to it.
Author
Owner

@esatterwhite commented on GitHub (Nov 13, 2025):

It currently only runs on bun exclusively. There are no plans to support other runtimes, though I am open to it.

Can we make plans? 😃

<!-- gh-comment-id:3528005240 --> @esatterwhite commented on GitHub (Nov 13, 2025): > It currently only runs on bun exclusively. There are no plans to support other runtimes, though I am open to it. Can we make plans? 😃
Author
Owner

@kommander commented on GitHub (Nov 13, 2025):

Sure, the zig.ts exports a RenderLib interface and a resolveRenderLib function, both is used throughout the codebase. It also eagerly loads the native lib to reduce startup time.

So to provide a NAPI module one Just™ would have to solve this incomplete list:

  • wrap the native lib.zig c abi to build .node modules, using the static libs from then next step
    • expose a RenderLib compatible interface
    • in resolveRenderLib and for the eager loading if !bun return the napi lib
    • Note: the module level ffi native path resolution at the top of zig.ts needs to be conditional and for non-bun dynamically import the RenderLibcompatible .node module instead of the native ffi lib
  • extend the build.zig to also build static versions
  • in core/scripts/build.ts
    • also build the .node modules as a step
    • add the .node modules to the respective binary npm packages
    • add the .node modules to artifacts
    • add tha t to the pipeline build.yml
    • in release.yml
      • bundle the static libs from artifacts in the zips with the dynamic ones
  • extend the "build & test" workflows to run a matrix, also running the tests on napi supported runtimes

And the napi needs to be maintained to stay in sync with the native interface, which is far from stable and changes almost daily, so something generated would work best if possible, so it can be regenerated when the native interface changes.

Note: this does not consider the whole 3D part which currently also uses an FFI lib, which needs to be switched out to some napi webgpu module as well. Deno has its own webgpu bindings. All of the webgpu interfaces should be mostly compatible though.

<!-- gh-comment-id:3529417164 --> @kommander commented on GitHub (Nov 13, 2025): Sure, the `zig.ts` exports a `RenderLib` interface and a `resolveRenderLib` function, both is used throughout the codebase. It also eagerly loads the native lib to reduce startup time. So to provide a NAPI module one Just™ would have to solve this incomplete list: - wrap the native `lib.zig` c abi to build `.node` modules, using the static libs from then next step - expose a `RenderLib` compatible interface - in `resolveRenderLib` and for the eager loading if !bun return the napi lib - Note: the module level ffi native path resolution at the top of `zig.ts` needs to be conditional and for non-bun dynamically import the `RenderLib`compatible `.node` module instead of the native ffi lib - extend the `build.zig` to also build static versions - in `core/scripts/build.ts` - also build the `.node` modules as a step - add the `.node` modules to the respective binary npm packages - add the `.node` modules to artifacts - add tha t to the pipeline `build.yml` - in `release.yml` - bundle the static libs from artifacts in the zips with the dynamic ones - extend the "build & test" workflows to run a matrix, also running the tests on napi supported runtimes And the napi needs to be maintained to stay in sync with the native interface, which is far from stable and changes almost daily, so something generated would work best if possible, so it can be regenerated when the native interface changes. **Note:** this does not consider the whole 3D part which currently also uses an FFI lib, which needs to be switched out to some napi webgpu module as well. Deno has its own webgpu bindings. All of the webgpu interfaces should be mostly compatible though.
Author
Owner

@remorses commented on GitHub (Nov 13, 2025):

It would be easier to wait for Node.js to add something like Bun ffi into core: https://github.com/nodejs/node/pull/57761

<!-- gh-comment-id:3529677851 --> @remorses commented on GitHub (Nov 13, 2025): It would be easier to wait for Node.js to add something like Bun ffi into core: https://github.com/nodejs/node/pull/57761
Author
Owner

@kommander commented on GitHub (Nov 14, 2025):

Probably, would have to check how compatible the interfaces are, as ffi != ffi, so it likely still needs a compat layer for different runtimes.

<!-- gh-comment-id:3534675469 --> @kommander commented on GitHub (Nov 14, 2025): Probably, would have to check how compatible the interfaces are, as ffi != ffi, so it likely still needs a compat layer for different runtimes.
Author
Owner

@esatterwhite commented on GitHub (Nov 15, 2025):

Maybe support for deno first, node later when the playing field is a bit more level?

<!-- gh-comment-id:3536070431 --> @esatterwhite commented on GitHub (Nov 15, 2025): Maybe support for deno first, node later when the playing field is a bit more level?
Author
Owner

@kommander commented on GitHub (Nov 15, 2025):

That could be more realistic than NAPI I think

<!-- gh-comment-id:3536736770 --> @kommander commented on GitHub (Nov 15, 2025): That could be more realistic than NAPI I think
Author
Owner

@esatterwhite commented on GitHub (Nov 16, 2025):

Out of curiosity, Why does this project need access to the gpu? Wouldn't it make more sense to leave that up to user to install gpu accelerated terminals if that is what they want?

It seems a bit outside the scope of what a tui framework should care about. But 🤷 I don't have a leg to stand on here.

<!-- gh-comment-id:3538749229 --> @esatterwhite commented on GitHub (Nov 16, 2025): Out of curiosity, Why does this project need access to the gpu? Wouldn't it make more sense to leave that up to user to install gpu accelerated terminals if that is what they want? It seems a bit outside the scope of what a tui framework should care about. But 🤷 I don't have a leg to stand on here.
Author
Owner

@kommander commented on GitHub (Nov 16, 2025):

It doesn't need it for anything non-3D, the threejs stuff is completely optional for the core, just a fun gimmick currently. It doesn't load the 3D module if it's Not explicitly imported, so it could be made a separate package. I was just mentioning it for completeness.

<!-- gh-comment-id:3539021567 --> @kommander commented on GitHub (Nov 16, 2025): It doesn't need it for anything non-3D, the threejs stuff is completely optional for the core, just a fun gimmick currently. It doesn't load the 3D module if it's Not explicitly imported, so it could be made a separate package. I was just mentioning it for completeness.
Author
Owner

@joshuaboys commented on GitHub (Dec 29, 2025):

I am commenting here so I remember to keep checking in... was pretty excited to use opentui but will have to use ink for now so I can actually ship the product.. but I have added "move to opentui when they support Node or I support Bun"

Keep up the great work though! Looks awesome

<!-- gh-comment-id:3695669711 --> @joshuaboys commented on GitHub (Dec 29, 2025): I am commenting here so I remember to keep checking in... was pretty excited to use opentui but will have to use ink for now so I can actually ship the product.. but I have added "move to opentui when they support Node or I support Bun" Keep up the great work though! Looks awesome
Author
Owner

@remorses commented on GitHub (Dec 29, 2025):

Another benefit of using NAPI is easier porting to other high level languages without writing too much code: you can create a NAPI runtime for that language and load the addon with support for classes, async, objects, callbacks, etc

For example here I loaded the node-canvas npm package in Python!
https://github.com/remorses/napi-python/blob/main/examples/canvas-draw.py

<!-- gh-comment-id:3696029749 --> @remorses commented on GitHub (Dec 29, 2025): Another benefit of using NAPI is easier porting to other high level languages without writing too much code: you can create a NAPI runtime for that language and load the addon with support for classes, async, objects, callbacks, etc For example here I loaded the node-canvas npm package in Python! https://github.com/remorses/napi-python/blob/main/examples/canvas-draw.py
Author
Owner

@5hubham5ingh commented on GitHub (Jan 15, 2026):

Probably, would have to check how compatible the interfaces are, as ffi != ffi, so it likely still needs a compat layer for different runtimes.

Hi, stumbled here while looking for ways to use the lib in txiki.js and I got it to work, miserably I must add :-)

So, a compat layer would be awesome. Something like:

  • Abstract base class / interface for the FFI operations
  • Runtime-specific implementations: Deno, Bun, txiki.js (all already have good FFI), and later Node when it matures

Using txiki.js to build and distribute compiled bytecode or binary would be great and a big advantage over other runtimes consuming memory and having binary sizes in the range of triple-digit mbs compared to a couple of mbs for txiki.js.

<!-- gh-comment-id:3754485121 --> @5hubham5ingh commented on GitHub (Jan 15, 2026): > Probably, would have to check how compatible the interfaces are, as ffi != ffi, so it likely still needs a compat layer for different runtimes. Hi, stumbled here while looking for ways to use the lib in txiki.js and I got it to work, miserably I must add :-) So, a compat layer would be awesome. Something like: - Abstract base class / interface for the FFI operations - Runtime-specific implementations: Deno, Bun, txiki.js (all already have good FFI), and later Node when it matures Using txiki.js to build and distribute compiled bytecode or binary would be great and a big advantage over other runtimes consuming memory and having binary sizes in the range of triple-digit mbs compared to a couple of mbs for txiki.js.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/opentui#3
No description provided.