DEV Community

Nicolas Rannou
Nicolas Rannou

Posted on

4 1

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!

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

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!

Heroku

This site is powered by Heroku

Heroku was created by developers, for developers. Get started today and find out why Heroku has been the platform of choice for brands like DEV for over a decade.

Sign Up

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay