Skip to content

feat(windows-napi): take Node-API from the modules NAPI_HOST_MODULES names - #46

Draft
NathanWalker wants to merge 1 commit into
mainfrom
feat/napi-host-modules
Draft

NathanWalker wants to merge 1 commit into
mainfrom
feat/napi-host-modules

Conversation

@NathanWalker

@NathanWalker NathanWalker commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

Summary

windows-napi can now run in a host whose executable doesn't export Node-API. The embedder lists the modules that do in NAPI_HOST_MODULES, ;-separated and in priority order, and napi-sys takes each napi_* from the first module that exports it.

Why

React Native for Windows needs it (NativeScript/runtimes#112). @nativescript/react-native runs the addon in a Hermes runtime made through hermes.dll's jsr_* API:

  • hermes.dll has the engine half of Node-API (js_native_api.h, 115 functions), but none of Node's (node_api.h). napi-rs calls napi_create_threadsafe_function and napi_add_env_cleanup_hook during registration (create_custom_gc), so the addon panicked with "Node-API symbol has not been loaded".
  • The React Native module implements Node's half itself and sets NAPI_HOST_MODULES=<its DLL>;<hermes.dll>.

Change

  • packages/vendor/napi-sys (load_all): with NAPI_HOST_MODULES set, load each listed module, and load the symbol groups from them in reverse order. A symbol a library lacks keeps its earlier value, so each one ends up from the first library that has it. Without the variable, nothing changes.
  • The workspace patches napi-sys with the vendored copy ([patch.crates-io]), as windows-hermes already did, so windows-napi gets it.
  • windows-napi/README.md: "Embedding outside Node".

Evidence

Built with cargo build -p windows-napi --release. The resulting windows_napi.dll ran in a react-native-windows 0.83.2 app through @nativescript/react-native's Windows module: sync WinRT, awaited async operations, console and errors all work (details in the runtimes PR).

Found along the way (not fixed here)

  • GUID marshalling in the Node-API engine. NativeType::try_from("Guid") returns Pointer (runtime/src/value.rs). A string argument then can't be parsed as a pointer, so the callee gets a null or zero GUID: BitmapEncoder.CreateAsync(id, stream) fails with WINCODEC_ERR_COMPONENTNOTFOUND (0x88982F50) for any form of the id. On return, a 16-byte GUID is written into an 8-byte pointer slot and then read as an object pointer, which crashes (BitmapEncoder.JpegEncoderId, BitmapCodecInformation.CodecId). The classic engine special-cases Guid (guid_ptr_to_js_object, parse_guid_str); the Node-API engine needs the same for parameters (napi_parse_arg) and return slots (method_call.rs / property_call.rs size it as a pointer).
  • XAML stops laying out after the last island closes. Once every XamlWindow on a thread has closed, new ones stay 0×0 (XamlRoot.IsHostVisible false). A hidden, never-closed island works around it.

…names

An embedder whose executable doesn't export Node-API can now run the
addon: it lists the modules that do in NAPI_HOST_MODULES (';'-separated,
in priority order), and napi-sys takes each napi_* from the first one
that exports it.

React Native for Windows needs this. @nativescript/react-native runs the
addon in a Hermes runtime made through hermes.dll's jsr_* API: hermes.dll
has the engine half of Node-API (js_native_api.h) and the React Native
module implements Node's half (threadsafe functions, cleanup hooks,
buffers), so it sets NAPI_HOST_MODULES=<its DLL>;<hermes.dll>.

The workspace now patches napi-sys with the vendored copy, as
windows-hermes already did. Without NAPI_HOST_MODULES nothing changes:
symbols come from this module if it exports them, else the process.
@coderabbitai

coderabbitai Bot commented Nov 6, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 447efbf5-8681-4bf3-8912-7f2e7c5c23cb

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

This branch has not been deployed

No deployments
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