Web technologies evolve fast, sometimes so fast that updating one dependency in a project may crash the whole thing because other dependencies didn't catch up already.
That was the case in a lab course I'm doing based on web3.js and React, which is more than a year old. When I downloaded the source and began updating the package dependencies, I started to experience the dependency/deprecacy hell.
The downloaded lab project depended on React v16.11.0 and Web3 v1.2.6, and for an updated reference, the current versions of both pagackes are v18 and v1.7.4 respectively.
I'm not going to detail every error I went through, because they were so many, and the (not) funny thing was that after fixing one, others kept appearing; but I'll show you the path to run an app with the latest web3 and react together.
Before the procedure
Since the lab didn't have so many other dependencies, I opted to do a clean install.
I went to the web3.js github repo (https://github.com/ChainSafe/web3.js), and there I found the first warning about known issues:
The latests versions of create-react-app don't include NodeJS polyfills
This was the culprit of seeing errors like "Uncaught ReferenceError: Buffer is not defined" and so on when trying to run the lab the first time.
The proposed solution in the web3 repo is to install a package named react-app-rewired (which allows tweaking webpack configs without using the 'eject' command) along with these other packages, in a manual way:
process
crypto-browserify
stream-browserify
assert
stream-http
https-browserify
os-browserify
url
buffer
The procedure
Delete package.json, package.-lock.json and the node_modules folder, and install these packages manually:
npm i react-app-rewired
npm i --save-dev crypto-browserify
npm i --save-dev stream-browserify
npm i --save-dev assert
npm i --save-dev stream-http
npm i --save-dev https-browserify
npm i --save-dev os-browserify
npm i --save-dev url
npm i --save-dev buffer
npm i web3
Modify the scripts in package.json to use react-app-rewired. The packages with a minus (-) sign should be removed from the file, the ones with the plus (+) sign should be added.
"scripts": {
- "start": "react-scripts start",
+ "start": "react-app-rewired start",
- "build": "react-scripts build",
+ "build": "react-app-rewired build",
- "test": "react-scripts test",
+ "test": "react-app-rewired test",
"eject": "react-scripts eject"
}
Create a webpack.config.js file in the root folder, with these contents:
module.exports = {
target: 'node'
}
This defines the environment for webpack compilation to a Node.js environment (as explained in the documentation at https://webpack.js.org/concepts/targets/), so it will make use of require to load chunks and not touch built-in modules like fs and path. Follow by creating a config-overrides.js file used by react-app-rewired (also in the root folder of the project, not under /src), with this content:
webpack = require("webpack")
module.exports = function override(config) {
const fallback = config.resolve.fallback || {};
Object.assign(fallback, {
"crypto": require.resolve("crypto-browserify"),
"stream": require.resolve("stream-browserify"),
"assert": require.resolve("assert"),
"http": require.resolve("stream-http"),
"https": require.resolve("https-browserify"),
"os": require.resolve("os-browserify"),
"url": require.resolve("url"),
"buffer": require.resolve("buffer")
})
config.resolve.fallback = fallback;
config.ignoreWarnings = [/Failed to parse source map/];
config.plugins = [
...config.plugins,
new webpack.ProvidePlugin({
Buffer: ["buffer", "Buffer"],
}),
new webpack.ProvidePlugin({
process: "process/browser",
}),
]
return config;
}
The line in bold was added in order to avoid warnings about map files missing when the app is run; you may remove it if safely. Finally, add a last file in the src folder named polyfill.js (tip taken from https://github.com/ChainSafe/web3.js/issues/4659) with this content:
import Buffer from 'buffer';
window.global = window;
global.Buffer = Buffer;
global.process = {
env: { DEBUG: undefined },
version: '',
nextTick: require('next-tick')
};
And then, reference this file in your index.js:
import './polyfill';
This last step is required to stop seeing errors like 'Buffer is not defined' when starting the application with npm start. So that's it, after struggling for some hours with this problem, I decided to put it all together to help others not to waste precious time. Now you can focus on the fun stuff!
Comments