How to Install React Native Skia with Expo for Web and Native
Tags: programming, reactnative, skia, expogo
Published: 2024-04-23 03:56:17

---
title: How to Install React Native Skia with Expo for Web and Native
published: true
date: 2024-04-22 12:15:13 UTC
tags: Programming,reactnative,skia,expogo
canonical_url: https://www.amarjanica.com/how-to-install-react-native-skia-with-expo-for-web-and-native
---

This post features a really simple skia graphics but details instructions for installing react native skia on the expo go and expo web. Guide builds on top of the [expo router tabs demo](https://docs.expo.dev/router/advanced/tabs/) app and saves you time and frustration.

## Intros, what’s what?

**Skia** is a powerful open source graphics engine and library. It’s widely used in systems like Google Chrome, Android, iOS and many others.

**Expo** is a platform for building native apps for Android, iOS and the web with javascript/typescript and React Native. When devs go with expo instead of react native, they usually choose managed workflow. Managed workflow means most or all of the native code is hidden from you, you don’t need to worry about that, just type your React code and you’re done.

**Expo Go** is a mobile client app which lets you open and test projects while developing them. When you make changes to your code, those changes are immediately visible in the Expo Go app on your mobile device without needing a full reload of the app, preserving the current state. I believe other word for this feature is **hot reload**.

**Expo Router** is a file-based router for React Native and web applications. It allows you to manage navigation between screens in your app. Architecture of the routes and layout is very similar, if not the same as [next.js app router](https://nextjs.org/docs/app).

## Requirements

Configured Android SDK on your machine. Take a look at [windows](https://www.amarjanica.com/configure-android-sdk-environment-on-windows-11)or [linux](https://www.amarjanica.com/manually-install-android-sdk-on-ubuntu)instructions if you need step by step guide (also recorded on Youtube).

## Initialize the project

You can skip this step if you already have setup an expo project. I’m using the expo tabs template which includes a basic tab navigator setup, providing a structured layout and navigation system right from the start.

```
npx create-expo-app@latest --template tabs@50
```

## Install Skia

When installing dependencies on expo, usually you would install with `npx expo install` instead of `npm `or `yarn`. _Reason for this approach is compatibility and automatic configuration._ When issuing expo install, expo will pull the version which is known to work correctly with the version of sdk you are using. Also, expo will sometimes modify the native code or configuration files accordingly.

In an ideal world, right?

From my experience, this is not always the case. In the case of skia as authors mention:

> Metro and expo-router support is available from v0.1.240 and onwards. If you are using v0.1.221 (recommended version for Expo SDK 50), you can use [this patch](https://github.com/Shopify/react-native-skia/files/14357144/%40shopify%2Breact-native-skia%2B0.1.221.patch) (using [`patch-package`](https://www.npmjs.com/package/patch-package).
> 
> <cite>https://shopify.github.io/react-native-skia/docs/getting-started/web/#expo</cite>

Version of sdk 50 will install 0.1.221 which does not work without an additional patch.

My solution is to use a newer version and ignore expo-doctor warnings.

```
npm i --save @shopify/react-native-skia@0.1.240
npx expo install react-native-reanimated
```

Skia depends on `react-native-reanimated`, which is not installed without explicitly declaring it in `package.json`.

## Configure Skia

React native skia does not work without canvaskit.wasm, which needs to be stored somewhere in the expo app. Since I’m using the expo router setup, static files can be stored in public directory.

Adding `”postinstall”: “npx setup-skia-web public”` makes the wasm file accessible.

There’s one fun error that occurs after the setup. I’ve lost an hour trying to debug and polyfill:

> The package at “node\_modules\canvaskit-wasm\bin\full\canvaskit.js” attempted to import the Node standard library module “fs”.  
> It failed because the native React runtime does not include the Node standard library.
> 
> <cite>https://docs.expo.dev/workflow/using-libraries/#using-third-party-libraries</cite>

Self explanatory message, react native needs a workaround for standard node library like fs and path.

React Native does not include Node.js’s standard library. Usual solution would be to polyfill the standard library. But the real culprit here is the `canvaskit-wasm` module setup and not the lack of the standard Node library. Thanks to _[kimchouard](https://github.com/kimchouard/rn-skia-metro-web-example/blob/main/path-fs-canvaskit-postinstall.js)_, there’s a workaround for this issue (just copying the piece here to see what’s going on):

```
/**
 * Original code by https://github.com/kimchouard/rn-skia-metro-web-example/blob/main/path-fs-canvaskit-postinstall.js
 */
const fs = require('fs');
const path = require('path');

const packageJsonPath = path.join(__dirname, 'node_modules', 'canvaskit-wasm', 'package.json');
const packageJson = require(packageJsonPath);

packageJson.browser = {
    fs: false,
    path: false,
    os: false,
};

fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
```

canvaskit-wasm has no place using fs in native and web since we point to wasm file and also run `npx setup-skia-web public` as part of postinstall.

Create or modify _metro.config.js_ and add the following:

```
const { getDefaultConfig } = require('expo/metro-config');

const config = getDefaultConfig(__dirname, {
    isCSSEnabled: true,
});

config.resolver.assetExts.push('wasm');
config.transformer.getTransformOptions = async () => ({
    transform: {
        experimentalImportSupport: false,
        inlineRequires: true,
    },
});

module.exports = config;
```

This code customizes the Metro bundler configuration by adding support for WebAssembly (.wasm) files as assets. It also improves performance by inlining `require()` calls and disables experimental import features. I don’t know why it doesn’t work without custom transform rules.

## Making it work for the Web

This is where `LoadSkiaWeb` comes handy. I’d recommend adding this code in the root \_layout if you need it accessible in your entire app.

```
_layout.ts
useEffect(() => {
    if (Platform.OS === 'web') {
      LoadSkiaWeb({ locateFile: () => '/canvaskit.wasm' })
        .then(() => {
          setLoaded(true);
        })
        .catch((err) => console.error(err));
    } else {
      setLoaded(true);
    }
  }, []);
```

## Conclusion

Sometimes expo acts fishy for no apparent reason (like the `Cannot read properties of undefined (reading ‘Matrix’)`). Then the only solution is to [clear the bundler cache](https://docs.expo.dev/troubleshooting/clear-cache-windows/) and reinstall/rebuild the app. Anyway, all source code to install and configure react native skia on web and on native [is available at my github repo](https://github.com/amarjanica/react-native-skia-expo-demo). Also I recorded a YT tutorial to make it easier to follow the setup.

<iframe title="React Native Skia on Expo Go and Web" width="750" height="422" src="https://www.youtube.com/embed/Md1sHpf1_AM?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>