Skip to content

fix(🐛): install the native module before the flag constants are read - #530

Merged
wcandillon merged 2 commits into
wcandillon:mainfrom
mlecoq:fix/constants-before-install
Oct 15, 2026
Merged

wcandillon merged 2 commits into
wcandillon:mainfrom
mlecoq:fix/constants-before-install

Conversation

@mlecoq

@mlecoq mlecoq commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

The bug

The flags the package exports from src/constants.ts (GPUBufferUsage, GPUTextureUsage, GPUShaderStage, GPUColorWrite, GPUMapMode) are all undefined at runtime.

constants.ts reads them from globalThis while it is evaluated. main/index.tsx reaches it through its own imports (../install imports ./constants) before its body calls WebGPUModule.install(), because every import of a module is evaluated before that module's body. So the globals don't exist yet when constants.ts reads them, and the comment there (which says ./main installs first) doesn't hold.

Code that follows the documented pattern, importing a flag into a worklet, captures undefined. For example, @azzapp/react-native-skia-video 1.0 creates its frame textures in a worklet and gets Cannot read property 'RENDER_ATTACHMENT' of undefined. In a release build, that exception thrown from a frame callback aborts the app. We saw it on an iPhone as soon as a video was shown.

The fix

  • WebGPUModule.install() moves to main/installNative.ts, which main/index.tsx imports first.
  • That import is a bare import "./installNative". An import with bindings can be deferred to its first use by inlineRequires; a bare one stays in place.
  • The "install() returned … but RNWebGPU global is not available" warning moves with the install, so its message doesn't change.
  • The comment in constants.ts now describes the actual order.

Verification

  • I bundled an app with Metro (expo export --platform ios, production) against these sources. The install module is now required first in main/index.tsx, before ../install and ../constants. Before the change, ../install → ./constants was evaluated first.

The flags the package exports (GPUBufferUsage, GPUTextureUsage,
GPUShaderStage, GPUColorWrite, GPUMapMode from src/constants.ts) were all
undefined. constants.ts reads them from globalThis while it is evaluated,
and main/index.tsx reached it through its own imports (../install imports
./constants) before its body called WebGPUModule.install(): every import of
a module is evaluated before its body.

Code following the README pattern, importing the flags into a worklet,
captured undefined: `Cannot read property 'RENDER_ATTACHMENT' of undefined`
on the first texture created from a worklet, which aborts a release build
when it happens in a frame callback.

The install moves to main/installNative.ts, the first import of
main/index.tsx, and a bare one so that inlineRequires cannot defer it.
Checked in a production Metro bundle (expo export, iOS): the install module
is now required first, before ../install and ../constants.

The example app passes the exported flags to the E2E context, and
Constants.spec.ts checks they are the installed globals (native app only).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K65ZmjbaHYsZuwbq9E8S9X
@wcandillon
wcandillon self-requested a review October 15, 2026 05:45
…st mock the flag constants

- `src/index.tsx` starts with a bare `import "./main/installNative"` (the
  shape of react-native-skia's `import "./skia/NativeSetup"`), so the order
  of the `export *` lines no longer decides whether `constants.ts` sees the
  globals. `installNative.web.ts` carries the RNWebGPU polyfill so web never
  reaches the TurboModule.
- `installNative.ts` throws when `RNWebGPU` is missing after `install()`
  instead of warning: nothing works past that point.
- `install.ts` reads `RNWebGPU.gpu` at module scope; the holder and
  `provideGPUForInstall` only existed to survive the old evaluation order.
- `mock.ts` defines the spec bit values of the five flag objects and puts
  them on globalThis; it used to re-export `./constants`, which nothing
  installs under Jest.
@wcandillon
wcandillon merged commit 5b83e2b into wcandillon:main Oct 15, 2026
4 checks passed
@wcandillon

Copy link
Copy Markdown
Owner

Thanks a lot!

@mlecoq
mlecoq deleted the fix/constants-before-install branch October 15, 2026 06:59
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 0.15.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants