Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 8 additions & 44 deletions with-skia/components/async-skia.tsx
Original file line number Diff line number Diff line change
@@ -1,51 +1,15 @@
// Helper to ensure Skia loads or throws inside of React Suspense on web.
import React from "react";

import { use } from "react";
import { LoadSkiaWeb } from "@shopify/react-native-skia/lib/module/web";

function wrapPromise<T>(promise: Promise<T>) {
let status: "pending" | "success" | "error" = "pending";
let result: T | unknown;
let suspender = promise.then(
(r: T) => {
status = "success";
result = r;
},
(e: unknown) => {
status = "error";
result = e;
}
);
return {
read(): T {
if (status === "pending") {
throw suspender;
} else if (status === "error") {
throw result;
} else if (status === "success") {
return result as T;
}
throw new Error("Unexpected state");
},
};
}

const promiseMap = new Map();
let skiaPromise: Promise<void> | null = null;

const getSuspendingPromise = () => {
const id = "skia";
if (!promiseMap.has(id)) {
const loader = wrapPromise(LoadSkiaWeb());
promiseMap.set(id, loader);
return loader.read();
}

return promiseMap.get(id).read();
};

const getResolvedPromise = React.cache(getSuspendingPromise);
function loadSkia() {
if (!skiaPromise) skiaPromise = LoadSkiaWeb();
return skiaPromise;
}

export function AsyncSkia({}) {
getResolvedPromise();
export function AsyncSkia() {
use(loadSkia());
return null;
}
14 changes: 14 additions & 0 deletions with-skia/copy-canvaskit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// This script is used to copy canvaskit.wasm from node_modules to public folder

const fs = require("fs");
const path = require("path");

const publicFolder = path.join(process.cwd(), "public");
fs.mkdirSync(publicFolder, { recursive: true });

const wasmSrc = require.resolve("canvaskit-wasm/bin/full/canvaskit.wasm", {
paths: [require.resolve("@shopify/react-native-skia")],
});

const wasmDest = path.join(publicFolder, "canvaskit.wasm");
fs.copyFileSync(wasmSrc, wasmDest);
8 changes: 4 additions & 4 deletions with-skia/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@
"main": "expo-router/entry",
"scripts": {
"start": "expo start",
"postinstall": "mkdir public; cp $(node -p \"require.resolve('canvaskit-wasm/bin/full/canvaskit.wasm', { paths: [require.resolve('@shopify/react-native-skia')] })\") public/canvaskit.wasm",
"postinstall": "node copy-canvaskit.js",
"deploy": "npx expo export -p web && npx eas-cli@latest deploy"
},
"dependencies": {
"@shopify/react-native-skia": "2.2.12",
"expo": "^54.0.1",
"expo-linking": "^8.0.8",
"expo-router": "~6.0.0",
"expo-router": "~6.0.22",
"react": "19.1.0",
"react-dom": "19.1.0",
"react-native": "0.81.4",
"react-native-reanimated": "^4.1.3",
"react-native": "0.81.5",
"react-native-reanimated": "~4.1.1",
"react-native-safe-area-context": "^5.6.1",
"react-native-screens": "~4.16.0",
"react-native-web": "^0.21.0",
Expand Down