DEV Community

Nicolas Rannou
Nicolas Rannou

Posted on

WASM in Create-React-App 4 in 5mn (without ejecting)

First word

In this post, we will write some rust code, compile it to WASM and run it from a CRA4 application without ejecting.

Rust to WASM FTW

Why Rust? It's cool. There is a lot of hype around it so I decided to give it a go. The rust book and rust by examples were pretty useful to get an understanding of the basics.

Once I got my head around the basic concepts, time to look into the conversion to WASM. There is a lot of nice documentation out there (from the Rust official documentation of course ;)).

The recommendation is to use wasm-pack. That allows you to build and ship an importable WASM module in less than 2mn.

Create the project

$> wasm-pack new my-wasm-project $> cd my-wasm-project 
Enter fullscreen mode Exit fullscreen mode

Package and public (details)

$> wasm-pack build --scope nicolasrannou $> cd pkg /*make sure the package.json includes the right files. At the time I write this post some .js and .wasm files were missing.*/ $> npm publish --access=public 
Enter fullscreen mode Exit fullscreen mode

CRACO

To load the exported module I chose CRACO because it appears Create-react-app-rewired is not really maintained anymore and doesn't work well with CRA4.

Adding dependencies in your CRA4 project

$> cd my-cra4-project $> yarn add @nicolasrannou/my-wasm-project $> yarn add @craco/craco $> yarn add wasm-loader 
Enter fullscreen mode Exit fullscreen mode

Do not forget to update package.json by replacing react-scripts by craco.

Setup the config file

$> cat craco.config.js const { addBeforeLoader, loaderByName } = require('@craco/craco'); module.exports = { webpack: { configure: (webpackConfig) => { const wasmExtensionRegExp = /\.wasm$/; webpackConfig.resolve.extensions.push('.wasm'); webpackConfig.module.rules.forEach((rule) => { (rule.oneOf || []).forEach((oneOf) => { if (oneOf.loader && oneOf.loader.indexOf('file-loader') >= 0) { oneOf.exclude.push(wasmExtensionRegExp); } }); }); const wasmLoader = { test: /\.wasm$/, exclude: /node_modules/, loaders: ['wasm-loader'], }; addBeforeLoader(webpackConfig, loaderByName('file-loader'), wasmLoader); return webpackConfig; }, }, }; 
Enter fullscreen mode Exit fullscreen mode

Import the WASM code

$> cat App.tsx ... useEffect(async () => { const promise = await import("@nicolasrannou/my-wasm-project"); promise.greet(); }, []); ... 
Enter fullscreen mode Exit fullscreen mode

👋 Until next time!

Top comments (1)

Collapse
 
andrewjschoen profile image
Andrew Schoen

Thanks for this tutorial! I set up according to these instructions, but swapped out my own library instead of the greeter one (which exports a struct I want to use). I am getting an error right now, but I am not sure exactly if it has something to do with wasm bindings, craco, webpack, or some combination of the above. Basically, the error I get is:

./node_modules/@my_scope/my_pkg/my_pkg_lib_bg.js Attempted import error: '__wbg_jsmystruct_free' is not exported from './my_pkg_lib_bg.wasm' (imported as 'wasm'). 
Enter fullscreen mode Exit fullscreen mode

Any thoughts on what might be causing this? Thanks again!