react-native-skia icon indicating copy to clipboard operation
react-native-skia copied to clipboard

React Native Skia on Web - Unable to load with multiple tabs open at once

Open cubevis opened this issue 2 months ago • 1 comments

Description

Using WithSkiaWeb, having more then one tab opened at once, fallback attribute will trigger

I've also checked that canvaskit.wasm is correctly fetching in duplicated tab, so I guess it's just issue with WithSkiaWeb

React Native Skia Version

2.2.12

React Native Version

0.81.4

Using New Architecture

  • [x] Enabled

Steps to Reproduce

  1. Use WithSkiaWeb
import '@expo/metro-runtime'
import { WithSkiaWeb } from '@shopify/react-native-skia/lib/module/web';
import { fontsConfig } from './fontsConfig';
import { useFonts } from 'expo-font';
import UILoaderText from './components/UI/UILoaderText';


export default function App() {

  let location = window.location.origin

  /* -------------------------- 2. Load Project Font -------------------------- */
  const [fontsLoaded] = useFonts(fontsConfig);
  if (!fontsLoaded) return <UILoaderText text='Fonts' />;
  /* -------------------------------------------------------------------------- */


  return (
    <WithSkiaWeb
      getComponent={() => import("./AppCore")}
      opts={{
        locateFile: (file) => `${location}/${file}?v=${Date.now()}`
      }}
      fallback={<UILoaderText text='Loading skia web...' />}
    />
  );
}
  1. Duplicate Tab in browser
  2. Unable to pass Loading skia web

Snack, Code Example, Screenshot, or Link to Repository

import '@expo/metro-runtime'
import { WithSkiaWeb } from '@shopify/react-native-skia/lib/module/web';
import { fontsConfig } from './fontsConfig';
import { useFonts } from 'expo-font';
import UILoaderText from './components/UI/UILoaderText';


export default function App() {

  let location = window.location.origin

  /* -------------------------- 2. Load Project Font -------------------------- */
  const [fontsLoaded] = useFonts(fontsConfig);
  if (!fontsLoaded) return <UILoaderText text='Fonts' />;
  /* -------------------------------------------------------------------------- */


  return (
    <WithSkiaWeb
      getComponent={() => import("./AppCore")}
      opts={{
        locateFile: (file) => `${location}/${file}?v=${Date.now()}`
      }}
      fallback={<UILoaderText text='Loading skia web...' />}
    />
  );
}

cubevis avatar Nov 03 '25 15:11 cubevis

I fixed this using creating own UIWithSkiaWeb :

import React, { useEffect, useState } from "react";
import { View, Text } from "react-native";
import UILoaderText from "./UILoaderText";

interface UIWithSkiaWebProps {
  children: React.ReactNode;
  version?: string; // 0.40.0
}

export default function UIWithSkiaWeb({ children, version = "0.40.0" }: UIWithSkiaWebProps) {
  const [ready, setReady] = useState(false);

  useEffect(() => {
    if (typeof window === "undefined") return;

    const CDN = `https://cdnjs.cloudflare.com/ajax/libs/canvaskit-wasm/${version}/`;


    if ((window as any).CanvasKit) { /* If canva exists */
      setReady(true);
      return;
    }

    const script = document.createElement("script");
    script.src = CDN + "canvaskit.js";
    script.async = true;
    script.onload = () => {
      const CanvasKitInit = (window as any).CanvasKitInit;
      if (!CanvasKitInit) {
        console.error("CanvasKitInit not found after loading script.");
        return;
      }

      (window as any).CanvasKitPromise = CanvasKitInit({
        locateFile: (file: string) => CDN + file,
      });

      (window as any).CanvasKitPromise.then((ck: any) => {
        (window as any).CanvasKit = ck;
        setReady(true);
      });
    };

    document.body.appendChild(script);

    return () => {
      script.remove();
    };
  }, [version]);


  if (!ready) {
    return <UILoaderText text={"Loading skia web..."} />
  }


  return <>{children}</>;
}

Alternative add in index.html :

    <script src="https://unpkg.com/[email protected]/bin/canvaskit.js" ></script>
    <script>
      window.CanvasKitPromise = CanvasKitInit({
        locateFile: (f) =>
          'https://unpkg.com/[email protected]/bin/' + f,
      });
      window.CanvasKitPromise.then((ck) => {
        window.CanvasKit = ck;
      });
    </script>

cubevis avatar Nov 03 '25 22:11 cubevis