Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rust (wasm) support #6457

Open
bowd opened this issue Feb 19, 2019 · 14 comments
Open

Rust (wasm) support #6457

bowd opened this issue Feb 19, 2019 · 14 comments
Assignees

Comments

@bowd
Copy link

bowd commented Feb 19, 2019

I've just started to play around with this https://github.com/thomashorrobin/create-react-app-rust create-react-app fork that adds rust support. I had some problems with typescript using it and decide to rebase on top of the latest create-react-app to not waste time debugging for something that's already fixed here. While doing this I realised that the actual changes for rust seem minimal. I'm not sure if there was ever a discussion about folding this fork into this project. I couldn't find anything in the issues to that extent.

My question is: would it be of interest to include Rust (via WASM) support in this package directly, or maintain the separate fork? If there's interest I can rebase again and prepare the fork to be submitted as a PR. Thanks!

@petetnt
Copy link
Contributor

petetnt commented Feb 19, 2019

Hi @bowd!

Does the rust support require changes to the react-scripts or other internal tools or does it just change the scaffolding and add the relevant dependencies and build scripts?

@bowd
Copy link
Author

bowd commented Feb 20, 2019

No major changes as far as I can see what we're looking at is just some webpack loaders, some build script changes and scaffolding. I would modify the scaffolding to work similarly to the --typescript flag and the build based on detecting the Cargo.toml file. I will need to understand the changes made in that fork better and make sure I agree with all of them, and add tests of course.

@prichey
Copy link

prichey commented Mar 4, 2019

Not to co-opt this thread but for posterity, I wrote about a solution to this using react-app-rewired: https://prestonrichey.com/blog/react-rust-wasm/. Obviously vanilla CRA support for Wasm would be great but this might be a resource for others playing around in this space in the meantime.

@ponchofiesta
Copy link

@prichey I've tried your way but I get this:

../webassembly-tests-rust/pkg/webassembly_tests_rust_bg.wasm
Module parse failed: Unexpected section: 0xfe
You may need an appropriate loader to handle this file type.
Error: Unexpected section: 0xfe

Any advice? I found this issue webpack/webpack#8781 but I have no way to upgrade webpack, I think.

@prichey
Copy link

prichey commented Mar 14, 2019

@ponchofiesta Did you set your wasm-bindgen version as specified here? rustwasm/book#148 (comment)

@ponchofiesta
Copy link

Now it works. Great solution!

@ize8
Copy link

ize8 commented Mar 17, 2019

I get the same error message, even with explicitly setting wasm-bindgen version :( At the same time, ejecting the CRA would cause a flurry of other different problems, so I guess I need to wait until there is a more 'mainstream' option for rust->wasm->CRA

keep up the good work guys!

@stale
Copy link

stale bot commented Apr 16, 2019

This issue has been automatically marked as stale because it has not had any recent activity. It will be closed in 5 days if no further activity occurs.

@stale stale bot added the stale label Apr 16, 2019
@iansu iansu removed the stale label Apr 16, 2019
@iansu iansu self-assigned this Apr 16, 2019
@heyimalex
Copy link
Contributor

I'm really not sure is a good fit for CRA. Note that this is different than #4912, which is just asking for wasm support, whereas this is using rust-native-wasm-loader to have webpack actually compile rust code into wasm. IMO that's pretty niche.

@stale
Copy link

stale bot commented May 18, 2019

This issue has been automatically marked as stale because it has not had any recent activity. It will be closed in 5 days if no further activity occurs.

@stale stale bot added the stale label May 18, 2019
@rcoh
Copy link

rcoh commented Mar 2, 2020

FYI: https://prestonrichey.com/blog/react-rust-wasm/ works out-of-the-box with wasm-bindgen 0.2.58

@NicolasRannou
Copy link

NicolasRannou commented Dec 22, 2020

Also, if anybody interested, same as a link above but using craco and CRA 4 (as react-rewired seems to, unfortunately, be not actively maintained)
https://dev.to/nicolasrannou/wasm-in-create-react-app-4-in-5mn-without-ejecting-cf6

@yuichiroaoki
Copy link

wasm-loader has been archived.
https://github.com/ballercat/wasm-loader

@kkroening
Copy link

kkroening commented Sep 7, 2023

Rust wasm now works flawlessly out of the box with all of the modern, standard libraries/tools - EXCEPT for create-react-app.

I was stuck on this for several days, but there's an extremely small change to CRA (see below for fix/workaround) to make it work.

Proof of concept

Here's an extremely minimal example of a working app with webpack/typescript/wasm-pack out of the box (without create-react-app first).

Minimal Rust wasm:

wasm-pack new mywasm && (cd mywasm && wasm-pack build)

Extremely minimal webpack / typescript / wasm app:

mkdir -p mywebpack
cd mywebpack

npm init -y
npm install -D webpack webpack-cli ts-loader
npm install ../mywasm/pkg

cat << EOF > tsconfig.json
{
  "compilerOptions": {
    "moduleResolution": "node",
    "skipLibCheck": true,
    "target": "es2017"
  }
}
EOF

cat << EOF > webpack.config.js
module.exports = {
  entry: './index.ts',
  experiments: {asyncWebAssembly: true},
  module: {rules: [{test: /\.tsx?$/, use: 'ts-loader', exclude: /node_modules/}]},
  resolve: {extensions: ['.ts']},
};
EOF

echo '<html><body><script src="dist/main.js"></script></body></html>' > index.html

cat << EOF > index.ts
import * as mywasm from 'mywasm';
mywasm.greet();
EOF

npx webpack --mode=production
npx http-server -o

The wasm.greet() wasm example works as expected.

Obviously this is stripped down from a real app, but the point is that wasm works right out of the box with webpack + typescript with no special templating, no wasm-loader, no wasm-pack-loader, no async bootstrap.js loader module - no nonsense. You can layer in babel, tsx, etc. and everything continues to work. (Just be sure to enable the asyncWebAssembly experiment and target es2017 or later, as shown above)


However, when it comes to create-react-app, the same mywasm.greet() call fails miserably.

Minimal create-react-app / typescript / wasm app

# cd ..
npx create-react-app mycra --template typescript
cd mycra
npm install ../mywasm/pkg

In src/index.tsx, add the exact same exact same mywasm.greet() as the previous example:

import * as mywasm from 'mywasm';
mywasm.greet();

Now, when you run it (npm start, etc.), instead of executing the wasm, you'll see this in the console:

Uncaught TypeError: wasm.greet is not a function

So although this same code works flawlessly with all the stock libraries/tools, something in create-react-app gets in the way.

Cause

The issue is that rather than create-react-app having a lack of support for Rust/wasm per se, there's one specific part of it that does slightly too much: the webpack.config.js template inadvertantly intercepts the .wasm file in an asset/resource catch-all file loader:

            // "file" loader makes sure those assets get served by WebpackDevServer.
            // When you `import` an asset, you get its (virtual) filename.
            // In production, they would get copied to the `build` folder.
            // This loader doesn't use a "test" so it will catch all modules
            // that fall through the other loaders.
            {
              // Exclude `js` files to keep "css" loader working as it injects
              // its runtime that would otherwise be processed through "file" loader.
              // Also exclude `html` and `json` extensions so they get processed
              // by webpacks internal loaders.
              exclude: [/^$/, /\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/],
              type: 'asset/resource',
            },

This is a reasonable default in most cases because it ensures that miscellaneous files get included in the final bundle as raw data, but for wasm we need it to get out of the way of the ordinary webpack behavior.

Solution

The 'fix' is for to change the create-react-app webpack config exclude to also exclude .wasm files:

-              exclude: [/^$/, /\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/],
+              exclude: [/^$/, /\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/, /\.wasm$/],

Of course, create-react-app doesn't let you change the webpack config directly, but the usual CRACO and react-app-rewired are viable workarounds (... or just eject 😦)

Besides the CRACO/react-app-rewired/eject workarounds, perhaps it would make sense to become a permanent create-react-app change. A potential downside is that .wasm files are written separately from the main output js bundle file(s), but perhaps that's better in most cases anyways 🤷‍♂️ .

In any case, here's the workaround at last.

Workaround: CRACO

craco.config.js:

module.exports = {
  webpack: {
    configure: (webpackConfig, { env, paths }) => {
      // Enable `asyncWebAssembly` experiment for no-nonsense wasm import:
      !webpackConfig.experiments && (webpackConfig.experiments = {});
      webpackConfig.experiments.asyncWebAssembly = true;

      // Patch the catch-all 'file' loader to stay out of the way of `*.wasm` files:
      // https://github.com/facebook/create-react-app/issues/6457#issuecomment-1709519156
      const oneOfRule = webpackConfig.module.rules.find((rule) => rule.oneOf);
      const fileLoader = oneOfRule && oneOfRule.oneOf.find((rule) => rule.type === 'asset/resource');
      fileLoader && fileLoader.exclude.push(/\.wasm$/);

      return webpackConfig;
    },
  },
};

Usage:

npm install -D @craco/craco
npx craco start

Sorry for the long post, or if this is just rehashing what's already been said. Hopefully it helps save time for someone stuck on this issue too, so they don't have to bash their head against the wall for multiple days like me 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests