Fix Web3 Package Dependency Issues in React Using Polyfills

Fix Web3 Package Dependency Issues in React Using Polyfills

If you're on this page, you're probably in the middle of your create-react-app project hacking away, so let's skip the intro and get right to it!

The Overview

  1. Install react-app-rewired
  2. Identify the polyfill needed (e.g. stream).
  3. Check this list for what polyfill package to use (e.g. stream-browserify for stream) and install it.
  4. Configure config-overrides.js.
  5. Modify package.json to use react-app-rewired.
  6. Restart the server and enjoy!

The Error

I know. Is it frustrating? Luckily we have you covered.

Before Webpack 5 shipped, Webpack 4 automatically polyfilled a lot of core modules for Node in the browser. This system, despite its convenience, tucks large amounts of code into your build as well as prevents you from having control over the polyfills you will use.

This means that for Webpack 5, you have to choose which polyfill you'll use and configure Webpack with the polyfills you'll need.

Image from Webpack's website

The Poly– what? The Polyfills.

As we are on the edge of Web3 innovation, some older browsers can't keep up with modern browser functionalities. With this, we have pieces of code called polyfills that can be used to give older browsers some modern functionalities.

You can think of it as browser boosters to give older browsers a chance to keep up with today's innovations. (BLAST OFF! 🚀)

The Tutorial

The thirdweb Way

Use our create-react-app starter template to get you started with polyfills included.  I repeat, with polyfills included so you don't have to do anything else to set it up!

GitHub - thirdweb-example/cra-typescript-starter: thirdweb starter project with Create React App & TypeScript
thirdweb starter project with Create React App & TypeScript - GitHub - thirdweb-example/cra-typescript-starter: thirdweb starter project with Create React App & TypeScript

You can get started with these templates by running:

npx thirdweb create --app

The react-app-rewired Way

If you're too far into your project, and can't start with thirdweb's starter template, this one's for you.

1. Install react-app-rewired as dev dependency

yarn add --dev react-app-rewired # yarn
npm install --save-dev react-app-rewired # npm

2. Identify polyfills needed

The easiest and fastest way to identify what polyfills you need is to run your build and read the error logs.

yarn run start # yarn
npm run start # npm

Identify errors that contain:

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default. This is no longer the case. Verify if you need this module and configure a polyfill for it.

It's your indicator that you are currently experiencing a polyfill error. Now notice how stream is highlighted below together with a suggested solution for the polyfill?

It states that you can use resolve.fallback: { "stream": require.resolve(""stream-browserify)} to enable a polyfill for stream.

This is the same for other polyfills with the complete list in this Webpack repo on Github.

You can also solve this error by disabling the polyfill as suggested below:

Importate Note: Disabling the polyfill means some functions in your build may not work in older browsers.

3. Install missing dependencies

Now that you have identified that the missing polyfill is stream and its dependency isstream-browserify install it using your package manager.

yarn add --dev stream-browserify # yarn
npm install --save-dev stream-browserify # npm

4. Configure polyfills with config-overrides.js

We have identified that the polyfill that can't be found is stream and you can choose to either disable or enable it.

First create a file called: config-overrides.js in your root directory.

In order to enable the stream polyfill use stream: require.resolve("stream-browserify") in your config-overrides.js like below.

Tip: If you're wondering where "stream-browserify" came from, check this list over here.
const webpack = require("webpack");

module.exports = function override(config) {
  const fallback = config.resolve.fallback || {};

  Object.assign(fallback, {
    // ENABLE OR DISABLE YOUR POLYFILLS HERE
    stream: require.resolve("stream-browserify"),
  });

  config.resolve.fallback = fallback;
  config.plugins = (config.plugins || []).concat([
    new webpack.ProvidePlugin({
      process: "process/browser",
      Buffer: ["buffer", "Buffer"],
    }),
  ]);
  config.resolve.extensions.push(".mjs");
  config.module.rules.push({
    test: /\.m?js/,
    resolve: {
      fullySpecified: false,
    },
  });

  return config;
};

If you want to disable the stream polyfill use stream: false like below.

Importate Note: Disabling the polyfill means some functions in your build may not work in older browsers.
const webpack = require("webpack");

module.exports = function override(config) {
  const fallback = config.resolve.fallback || {};

  Object.assign(fallback, {
    // ENABLE OR DISABLE YOUR POLYFILLS HERE
    stream: false
  });

  config.resolve.fallback = fallback;
  config.plugins = (config.plugins || []).concat([
    new webpack.ProvidePlugin({
      process: "process/browser",
      Buffer: ["buffer", "Buffer"],
    }),
  ]);
  config.resolve.extensions.push(".mjs");
  config.module.rules.push({
    test: /\.m?js/,
    resolve: {
      fullySpecified: false,
    },
  });

  return config;
};

5. Modify package.json scripts to use react-app-rewired

Now that you're done installing react-app-rewired and you're done configuring your config-overrides.js it's time to change your package.json to use react-app-rewired like below:

Note: eject is intentionally left with react-scripts eject
  "scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-scripts eject"
  },

Restart your server and that's it! You're done! (SHEESH!)

The Conclusion

Giving the code you need straight on is quick and easy, but understanding polyfills will not only allow you to solve the bug but also give you perspective on why they matter.

But once again, you can always skip these, by using our create-react-app starter template with thirdweb.