How to: WebGL + WebAssembly in React with Typescript | PART 1

View this thread on: d.buzz | hive.blog | peakd.com | ecency.com
ยท@garoxยท
0.000 HBD
How to: WebGL + WebAssembly in React with Typescript | PART 1
![image.png](https://images.ecency.com/DQmXTrKL2LutgAA3Ta85Y3aSt8P3avhgpBwmWwxp6w67276/image.png)


## Introduction
In this tutorial, we will see how to set up a project with Rust-WASM, and effectively build and deploy a GatsbyJS site ๐Ÿค“.

According to webassembly.org, WebAssembly (aka WASM) is a binary instruction format for a stack-based virtual machine. In practice, it is a format upon which we can deploy performant code for demanding tasks that run in browsers.
Because WASM is a binary format, we need to compile other languages to it. Common options are C, C++, Rust, and AssemblyScript. This time we'll use Rust for the task.

## Requirements
For this project, you'll need Node (preferably with yarn) and [Rust](https://www.rust-lang.org/tools/install) installed, as well as [gatsby-cli](https://www.gatsbyjs.com/docs/reference/gatsby-cli/) and [wasm-pack](https://rustwasm.github.io/wasm-pack/installer/).

## Creating a Gatsby Project
To create our Gatsby project run the following commands

`gatsby new tutorial`
`cd tutorial`
`yarn start` (or npm start)

We can now go to http://localhost:8000/ and see the default gatsby page

 ![gatsby_default_starter](https://images.ecency.com/DQmY5foGcostq8XHp4UB2wg1iqevT9ZwozNK4KXLnJo5RBD/screen_shot_2021_01_24_at_22.18.40.png=200x)

Going back to the terminal, we are going to add a couple of dependencies which I will explain as we use them.

`yarn add @loadable/component react-hooks-lib`
`yarn add -D @types/loadable__component`

## Creating our Rust project
Now that we have Gatsby ready for our purposes we will create our rust project inside `tutorial/src`.

`cd src && cargo new wasm`

This will create a default rust project which we can extend to support wasm.

>Note: If you don't know anything about rust there is an amazing [Youtube Channel](https://www.youtube.com/channel/UCmBgC0JN41HjyjAXfkdkp-Q/videos) where you can learn the basics and beyond.

If everything went right up until this moment, you should be able to do `cd wasm` and then `cargo run`, the expected output should be `Hello, world!`

In order to compile to wasm we need to add the following lines to `Cargo.toml`
## 

```toml
# .
# .
# .
[lib]
crate-type = ["cdylib"]

[dependencies]
wasm-bindgen = "0.2"
```

Now we need to change our starting point. By default rust will use `main.rs` but our project will be a library project and therefore the starting point must be `lib.rs`. (For further explanation refer to this [video](https://www.youtube.com/watch?v=5F6pHtkWMxg)). To do this, simply delete `main.rs` and create a new file called `lib.rs`. We can populate that new file with the snippet from [rustwasm guide](https://rustwasm.github.io/docs/wasm-bindgen/print.html) to verify that everything is working as it should.


```rust
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern "C" {
    fn alert(s: &str);
}

#[wasm_bindgen]
pub fn greet(name: &str) {
    alert(&format!("Hello, {}!", name));
}
```

run `wasm-pack build` to build our wasm code. You'll see a pkg folder inside wasm, this contains all the files we need, you can take a look at `wasm.d.ts` to see types declarations.

You should see
```ts
export function greet(name: string): void;
```

Hold on with your rust code for a while because we need to go back to gatsby

## Back to Gatsby
Run `cd ..` (assuming you were on `tutorial/src/wasm`)

Let's rename `tutorial/src/pages/index.js` to `tutorial/src/pages/index.tsx` (Restart gatsby if you get any errors)

Create a types folder inside src and create a file called `WASM.ts` with the next line:

```ts
export type IWASMModule = typeof import("../wasm/pkg/wasm")
```
This is a bit hacky since, as we will see, WASM must be imported dynamically and Gatsby will have trouble if we don't use a clever hack.

Now back to our index.tsx, we will use *loadable* to import WASM dynamically, 
 ```tsx 
/* index.tsx */
/*
.
.
.
*/
import loadable from "@loadable/component"
import { IWASMModule } from "../types/WASM"

const WASMModule = loadable.lib(
  () => import("" + "../wasm/pkg/wasm") as Promise<IWASMModule>
)

```
WASMModule is now a component which have a callback as a children, meaning that we can now pass the entire WASM module or only some parts of it as a prop to other components.

As an example we will use a button that calls the greet method. 

```tsx
    <WASMModule>
      {({ greet }) => <button onClick={() => greet("ruuuuust")}>press me</button>}
    </WASMModule>
```

>Note that if you hover over greet you get the exact type ![screen_shot_2021_01_25_at_10.59.30.png](https://images.ecency.com/DQmVXQtQE7RLV7sKA1HyZopaiD7rw3Wu6z5pMmnomAkR6sW/screen_shot_2021_01_25_at_10.59.30.png)

The full code will looks like something like this 
```tsx
import React from "react"

import Layout from "../components/layout"
import SEO from "../components/seo"
import loadable from "@loadable/component"
import { IWASMModule } from "../types/WASM"

const WASMModule = loadable.lib(
 () => import("" + "../wasm/pkg/wasm") as Promise<IWASMModule>
)
const IndexPage = () => (
  <Layout>
    <SEO title="Home" />
    <h1>Hi people</h1>
    <p>Welcome to your new Gatsby site.</p>
    <WASMModule>
      {({ greet }) => <button onClick={() => greet("ruuuuust")}>press me</button>}
    </WASMModule>
  </Layout>
)

export default IndexPage
```

And if you press the button

![screen_shot_2021_01_25_at_11.14.02.png](https://images.ecency.com/DQmU5kneoCb2D7XRix94VuDPcezmJBfaYDbifopsa89zZYH/screen_shot_2021_01_25_at_11.14.02.png)

Works like a charm ๐Ÿ”ฅ!

## Splitting functionality 

We want to keep things separated to make a robust solution. To do that we will create a `canvas.tsx` file inside `src/components`

We are going to use the useDidMount hook from `react-hooks-lib` to greet our user, later on we will use it to set up WebGL. We'll also leave a canvas element for future usage.

```tsx
import React, { FC,  } from "react"
import { useDidMount } from "react-hooks-lib"


import { IWASMModule } from "../types/WASM"

type CanvasComponent = FC<{
    greet: IWASMModule["greet"]
  }>

const Canvas: CanvasComponent = ({ greet }) => {
  useDidMount(() => {
    greet("from did mount")
  })
  return (
    <>
      <p>placeholder for part 2</p>
      <canvas  width="640" height="480"> </canvas>
    </>
  )
}

export default Canvas
```
Back to our index.tsx we import and use the new canvas component.

```tsx
import React from "react"

import Layout from "../components/layout"
import SEO from "../components/seo"
import loadable from "@loadable/component"
import { IWASMModule } from "../types/WASM"
import Canvas from '../components/canvas'

const WASMModule = loadable.lib(
 () => import("" + "../wasm/pkg/wasm") as Promise<IWASMModule>
)
const IndexPage = () => (
  <Layout>
    <SEO title="Home" />
    <h1>Hi people</h1>
    <p>Welcome to your new Gatsby site.</p>
    <WASMModule>
      {({ greet }) => <Canvas greet={greet} />}
    </WASMModule>
  </Layout>
)

export default IndexPage
```
Now every time refresh the page we will get 
![screen_shot_2021_01_25_at_11.24.55.png](https://images.ecency.com/DQmafdcqhxXDMBJhZXuXiBzFSqiif1NxetmDec58WqU3Mt5/screen_shot_2021_01_25_at_11.24.55.png)


## Part 2

We are now ready for part 2 where we will go deeper on rust and also review a bit of WebGL. It may seem like a lot to learn but possibilities are endless.
I will post part 2 in the next couple of days.
If you like it I would love to hear your feedback.
Happy coding!
๐Ÿ‘ , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,