Behold, the buzzwords:
The main goal here: To use Rust + WASM in a react app, inside a monorepo.
TLDR: visit the final product! https://github.com/cmdcolin/rust_react_monorepo_template. It is also deployed live here https://cmdcolin.github.io/rust_react_monorepo_template
mkdir template
cd template
git init
package.json
Then put this in the monorepo's root package.json
This sets our repo up as a "monorepo" with two "workspaces". one will be the
wasm code, in hello-wasm
, one will be an instance of create-react-app
create-react-app
instance inside the monorepoThis will make an app
subfolder inside our monorepo
wasm-bindgen
example and put it in a folder named hello-wasm
Download https://github.com/rustwasm/wasm-bindgen/tree/main/examples/hello_world to the hello-wasm folder
This link can help https://download-directory.github.io/?url=https%3A%2F%2Fgithub.com%2Frustwasm%2Fwasm-bindgen%2Ftree%2Fmain%2Fexamples%2Fhello_world
package.json
in the hello-wasm
folderhello-wasm
example to return a value instead of making an alertI changed the rust code to return a String value instead of making an alert box
hello-wasm
pkgGo into the hello-wasm
folder and run yarn build
. This creates a directory
named pkg
which has .wasm
files and .js
files. Now, the hello-wasm
folder is effectively a node package. We could publish this to NPM
(see
footnote 1)
hello-wasm
package to the app
dependenciesAdd "hello-wasm":"^1.0.0"
to the dependencies
array in app/package.json
.
This will refer to our local monorepo's rust wasm package!
create-react-app
As of writing, with webpack
v5/create-react-app
v5, you have to customize
the create-react-app
to add extra webpack
flags.
So, yarn add @craco/craco
in the app folder, then create this
craco.config.js
Note: this thread helped me to create the craco config https://github.com/Emurgo/cardano-serialization-lib/issues/295
Also see footnote 2 for more info
import()
to import the hello-wasm
greetingWe use a useEffect
hook to import the code asynchronously, and can call our
rust function, greet
, from javascript!
In order to greet an arbitrary person, I modified this slightly in the live demo. See https://github.com/cmdcolin/rust_react_monorepo_template/blob/master/app/src/App.tsx
Go into the app
folder, and then run yarn start
A screenshot of the app, showing the string "Hello Colin" which is generated via rust and wasm
My main aim was to demonstrate creating a "simple" monorepo setup showing how you can integrate Rust+WASM and React. Feel free to ask me any questions and go check out the repo!
https://github.com/cmdcolin/rust_react_monorepo_template
This article is quite helpful also, but uses a file:/ reference in their
package.json
while my approach uses a monorepo, it is fundamentally quite
similar though!
https://tkat0.github.io/posts/how-to-create-a-react-app-with-rust-and-wasm
hello-wasm
folder IS a npm package with wasm filesThe hello-wasm
folder can be published to NPM by itself. When consumers of the
package import the module, they would receive pkg/index.js
from the main
field in package.json
, and then pkg/index.js
in turn imports the
index.wasm
file. Then it is up to the consumers bundler to package that
correctly.
As of writing, I am using webpack
v5 (part of create-react-app
v5), which
has "native support" for wasm. Still, it is hidden behind a flag called
"experiments" (see first google result for webpack wasm here
https://webpack.js.org/configuration/experiments/) so I use @craco/craco
to
modify the webpack
config of create-react-app
v5 to add this.
Note also: The first time I wrote this, I used webpack
v4, which used a
slightly different workflow (used a special webpack
loader called
wasm-loader
)
You can also likely use similar techniques described in this article to
incorporate into next.js
since it also uses webpack
. If you have info on how
other bundlers use wasm, feel free to leave a comment.
Fundamentally, the .wasm
file has to be fetched asynchronously before it can
be run (it is not in my experience e.g. embedded as binary data inside a js
file) which means it would be difficult to use the wasm code as a synchronous
import.
There are hints that this may be possible but it would rely on the bundler embedding the wasm code in the js itself, or maybe top-level-await. If anyone has more info, feel free to leave a comment!
The hello-wasm
package does not automatically recompile when we are running
e.g. yarn start
in the app
folder. Therefore, changes to the rust requires
you to manually run yarn build
in the hello-wasm
folder. Just something to
be aware of
I first created an example of rust+wasm+react almost two years ago when creating a fractal viewer https://github.com/cmdcolin/logistic_chaos_map and it has some development notes on the stumbling blocks I faced https://github.com/cmdcolin/logistic_chaos_map/blob/master/NOTES.md
Yep! The hello-wasm
example generates typescript .d.ts
files! Check out the
hello-wasm/pkg/
folder after you build it! This was none of my doing, just a
built-in feature. PS: I highly recommend inspecting the pkg
folder that is
produced in the hello-wasm
build to help understand the details. I also
recommend reading the https://rustwasm.github.io/wasm-bindgen/ docs and if you
are getting started with rust, read the Rust Book along with doing rustlings
https://github.com/rust-lang/rustlings
This article was posted on reddit and is also a great resource especially about sync vs async webpack loading schemes for wasm
https://canvasapp.com/blog/building-modern-web-apps-with-rust-wasm-and-webpack/