Repository navigation
Conversation
Skia draws through a JSI binding to its C++ that throws at import in Node. Skia's own test support (jestEnv.js + jestSetup.js) loads CanvasKit, Skia compiled to WebAssembly, and mocks the package with lib/module/mock's Mock(CanvasKit): the JS Skia API backed by real Skia, with Canvas and SkiaPictureView as React Native Views. The preset does the same, under both engines, without configuration. - prepare() loads CanvasKit from the installed Skia's own dependency (an isolated layout does not hoist canvaskit-wasm), compiling the WebAssembly once per worker. Synchronous instantiation was measured and rejected: Emscripten attaches most of CanvasKit's API only when its runtime finishes initialising, after the synchronous part. - The module is Skia's Mock() plus Skia's Reanimated helpers (external/reanimated), which the real package exports and the mock omits, and a matchFont() that returns a font: over CanvasKit the real one throws for want of system fonts. - Named exports are the factory's names that the real package exports; the mock's leftovers from earlier releases stay off the named surface. Preset gains an optional async prepare(). The native setup awaits it. The mock-engine setup is also built as CommonJS and cannot await, so it builds a prepared preset's modules when preparation settles, the virtual module awaits that, and require() before then gets a PRESET_NOT_PREPARED error naming the fix rather than the real package's JSI failure. @shopify/react-native-skia 2.14.0 is a devDependency; root overrides replace its four prebuilt native binary packages (about 720 MB, read only by iOS/Android builds) with an empty stub.
The skia preset's module needs CanvasKit, which prepare() loads, and its graph reaches CanvasKit's WebAssembly heap: the walker now skips binary data, whose keys are millions of indices.
danfry1
force-pushed
the
feat/skia-preset
branch
from
October 10, 2026 18:54
4cb9075 to
c4e8d97
Compare
…nd runtimes
The forks and hot configs listed their own setup files and left out the
preset-readiness probe, so skia.test.tsx read undefined there. All three configs
that run tests-native/*.test.ts{,x} now take one list.
|
As of version >=2.15.0 and 3, the package name is |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds a
skiapreset, which is auto-detected when@shopify/react-native-skiais installed and works under both engines. It is the second half of #286, reported by @believer, which asked for Unistyles and Skia presets; Unistyles is #289.Closes #286.
Why
Importing Skia in a test threw
Native Skia Module failed to correctly install JSI Bindings. Skia's own test support loads CanvasKit, Skia compiled to WebAssembly, and mocks the package withMock(CanvasKit): the JS Skia API backed by real Skia. The preset uses that support directly instead of hand-writing a stand-in.Changes
src/presets/skia.tsprepare()loads CanvasKit from Skia's own dependency, compiling it once per worker.Mock(), plus Skia's Reanimated helpers. The real package exports those helpers but the mock omits them.matchFont()returns a font: over CanvasKit, which has no system fonts, the real one throws.src/presets/skia-exports.tsholds the named exports: the factory's names that the real package exports. The mock's leftovers from earlier releases are kept off the named surface.Preset.prepare?: () => Promise<void>require()before then throwsPRESET_NOT_PREPARED, naming the fix (src/preset-preparation.ts).tests-native/skia.test.tsxandtests/skia-preset.test.tsxcover real Skia geometry,Canvasrendering,matchFont, a Reanimated helper, and export-list sync.tests-native/support/preset-readiness.setup.ts) records whether CanvasKit loaded before user setup files ran. Without it, removing the nativeawaitwent unnoticed, because CanvasKit usually finishes first anyway.@shopify/react-native-skia@2.14.0is a devDependency. Rootoverridesreplace its four prebuilt native binary packages (about 720 MB, read only by the native builds) withscripts/native-binary-stub.Notes
presets: { skia: false }turns it off. I considered preparing only when a file imports Skia, but a CommonJS library thatrequire()s Skia couldn't wait for it, so I rejected that.presets.skiaand the optionalPreset.prepare.prepare().