Skip to content

fix(🌎): type MakeWebGPUCanvasContext as nullable and keep getNativeSurface() working after unmount - #548

Open
YevheniiKotyrlo wants to merge 3 commits into
wcandillon:mainfrom
YevheniiKotyrlo:fix/web-polyfill-null-context
Open

YevheniiKotyrlo wants to merge 3 commits into
wcandillon:mainfrom
YevheniiKotyrlo:fix/web-polyfill-null-context

Conversation

@YevheniiKotyrlo

@YevheniiKotyrlo YevheniiKotyrlo commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Problem

The global RNWebGPU.MakeWebGPUCanvasContext is typed to always return a context, but the web polyfill returns null without WebGPU support (#489). The polyfill hides that behind a @ts-expect-error over its whole object and a cast, and WebPolyfill.spec.ts declares its own Polyfill type to say so.

On the web, getNativeSurface() and MakeWebGPUCanvasContext read the canvas element with getElementById(...) as HTMLCanvasElement, so once the canvas has unmounted they throw TypeError: Cannot read properties of null (reading 'clientHeight') and (reading 'getAttribute'). Native answers a context it no longer knows with Canvas(nullptr, 0, 0): a 0n surface, every size 0, and DOM methods that do nothing.

Solution

getCanvasElement returns HTMLCanvasElement | null. For a missing element, getNativeSurface answers that same retired surface and MakeWebGPUCanvasContext returns null. The global type returns RNCanvasContext | null. The polyfill is annotated as the Pick of the four members it provides, so each is checked against the native module's type, and assigned with one cast for the members the web lacks. WebPolyfill.spec.ts drops its own Polyfill type, and CanvasContext.spec.ts's four device evals throw if native ever returns no context.

Tests

WebPolyfill.spec.ts gains two cases with getElementById answering null: a 0 × 0 surface whose DOM methods do not throw, and no context. On main both fail with those TypeErrors (2 failed, 2 passed); with the change, 4 passed.

Verification

yarn lint · yarn tsc · yarn turbo run build --filter='./packages/*' · the Expo template's web build · yarn test:plugin · yarn check-dawn · yarn build:docs. CI's Android e2e step (debug build, Metro with CI=true) on an Android 15 emulator (API 35): 221 of 223, main's 219 and the two new WebPolyfill.spec.ts cases; the two failures, the YUV cases of ExternalTextureColorSpace and NativeBufferWrapper, fail on main there too. On devices the whole suite passes, 223 of 223: on a Galaxy S23 (Android 14), and on an iPhone 12 Pro Max (iOS 27.0.1) built and run as CI's iOS job does on a simulator (Debug build, Metro with CI=true). main passes 221 of 221 on both. Not run here: the semantic-release dry run, which needs the repository's token.

…rface() working after unmount

The global RNWebGPU type said MakeWebGPUCanvasContext always returns a
context, while the web polyfill returns null without WebGPU support (wcandillon#489);
the polyfill hid that behind a @ts-expect-error over its whole object and a
cast. The type now says null, and the polyfill is checked as the members of
the native module it provides. On the web, getNativeSurface() and
MakeWebGPUCanvasContext read the canvas element without a null check, so
both threw a TypeError once the canvas had unmounted. getNativeSurface() now
answers what native answers for a context it no longer knows, a 0 x 0
surface whose DOM methods do nothing, and MakeWebGPUCanvasContext returns
null.

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