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

WIP feat: web CanvasKit hook loading method by conditional rendering

Open DaniHv opened this issue 1 year ago • 0 comments

This PR contains a proposal for an improved dev experience by adding a new way to load CanvasKit in web environments, which I found more "react friendly" (inspired by a lot of react dependencies that rely on loading stuff such as expo-font).  

Context

In the currently provided methods of loading CanvasKit, there are some issues or limitations:

  • <WithSkiaWeb />:

    • Every single component that needs Skia has to be wrapped on WithSkiaWeb, making the usage worse compared to how you would do in native.
    • The need for dynamic imports. Metro bundler doesn't handle well the dynamic imports from external modules (both node_modules and monorepos)
  • LoadSkiaWeb():

    • Won't work for apps that cannot defer loading the app. Cannot be used with expo router, since the registerComponent is handled internally by expo
    • You cannot parallelize async work by doing other things at the same time while loading CanvasKit, such as loading fonts.

Proposal

Instead, I propose to have a hook that can be called anywhere in the app, with no need to have different implementations between web and mobile, and just rely on conditional render to do whatever the developer wants to do in the meantime.

This hook can be an additional load method (to avoid breaking changes), but in the future, it could even replace the other two solutions, since it could offer the same -but in a better way-. (That's why the duplicated load promise state instead of relying on LoadSkiaWeb().)

The technical aspect. How does this work?

Well, currently Skia web relies on having the global variable CanvasKit to export the JsiSkApi wrapper/proxy that provides the same usage between native and web in terms of the exported Skia object, and since the current exported Skia uses directly the global variable it needs to be imported when the global variable has been loaded (by deferring the entire app or dynamic loading the components). (Sorry if I'm not using the best terms for describe the current implementation)

This solution provides a new function setSkiaCanvasKit that recreates the Skia object with the new CanvasKit instance, and that new object becomes available after the canvaskit has been loaded, without the need to defer the import of component that needs Skia.

What's next?

There are still some things to do regarding this PR, like adding examples and testing, and maybe the technical solution can be improved in some ways (while keeping the idea behind this proposal), but I would like to receive feedback before spending more time on it.

DaniHv avatar Jan 30 '24 23:01 DaniHv