无法将web3添加到React项目中

8

我正在尝试将Web3添加到React项目中。 我已经使用以下命令初始化了新项目:

gatsby new

然后,我安装了web3

npm install --save web3

当我在index.js文件中引入web3时

import Web3 from 'web3'

如果我打电话

gatsby develop

我遇到了一些奇怪的错误:

ERROR in ./node_modules/eth-lib/lib/bytes.js 9:193-227 模块未找到:在“/home/test/gatsby/test/test/node_modules/eth-lib/lib”中无法解析密码。

BREAKING CHANGE:webpack < 5默认情况下会包含 node.js 核心模块的polyfill。现在不再是这种情况。请验证是否需要此模块并为其配置一个polyfill。

如果您想包含一个 polyfill ,您需要: - 添加备用 'resolve.fallback: { "crypto": require.resolve("crypto-browserify") }' - 安装'crypto-browserify' 如果您不想包含polyfill,您可以使用一个空模块,如下所示: resolve.fallback: { "crypto": false }  @ ./node_modules/swarm-js/lib/api-browser.js 32:12-40  @ ./node_modules/web3-bzz/lib/index.js 24:12-31  @ ./node_modules/web3/lib/index.js 34:10-29  @ ./src/pages/index.js 9:0-24  @ ./.cache/this_is_virtual_fs_path/$virtual/async-requires.js 21:11-23:5  @ ./.cache/app.js 17:0-52 28:0-70 30:27-40 28:0-70

ERROR in ./node_modules/ethereumjs-util/dist/account.js 4:13-30 模块未找到:在“/home/test/gatsby/test/test/node_modules/ethereumjs-util/dist”中无法解析“assert”。

BREAKING CHANGE:webpack < 5默认情况下会包含 node.js 核心模块的polyfill。现在不再是这种情况。请验证是否需要此模块并为其配置一个polyfill。

如果您想要包含一个polyfill,您需要: - 添加后备选项'resolve.fallback: { "assert": require.resolve("assert/") }' - 安装'assert' 如果您不想包含一个polyfill,您可以使用一个空模块,像这样: resolve.fallback: { "assert": false }  @ ./node_modules/ethereumjs-util/dist/index.js 29:13-33  @ ./node_modules/ethereumjs-tx/dist/transaction.js 14:24-50  @ ./node_modules/ethereumjs-tx/dist/index.js 3:20-44  @ ./node_modules/web3-eth-accounts/lib/index.js 35:18-54  @ ./node_modules/web3-eth/lib/index.js 34:15-43  @ ./node_modules/web3/lib/index.js 30:10-29  @ ./src/pages/index.js 9:0-24  @ ./.cache/this_is_virtual_fs_path/$virtual/async-requires.js 21:11-23:5  @ ./.cache/app.js 17:0-52 28:0-70 30:27-40 28:0-70
错误在./node_modules/ethereumjs-util/dist/object.js 4:13-30中发生: 找不到模块:错误:无法解析'assert'在'/home/test/gatsby/test/test/node_modules/ethereumjs-util/dist'中。
重大变更:webpack <5默认情况下会包括node.js核心模块的polyfills。 现在不再是这种情况。请确认是否需要此模块并为其配置一个polyfill。
如果您想要包含一个polyfill,您需要: - 添加后备选项'resolve.fallback: { "assert": require.resolve("assert/") }' - 安装'assert' 如果您不想包含一个polyfill,您可以使用一个空模块,像这样: resolve.fallback: { "assert": false }  @ ./node_modules/ethereumjs-util/dist/index.js 45:13-32  @ ./node_modules/ethereumjs-tx/dist/transaction.js 14:24-50  @ ./node_modules/ethereumjs-tx/dist/index.js 3:20-44  @ ./node_modules/web3-eth-accounts/lib/index.js 35:18-54  @ ./node_modules/web3-eth/lib/index.js 34:15-43  @ ./node_modules/web3/lib/index.js 30:10-29  @ ./src/pages/index.js 9:0-24  @ ./.cache/this_is_virtual_fs_path/$virtual/async-requires.js 21:11-23:5  @ ./.cache/app.js 17:0-52 28:0-70 30:27-40 28:0-70

在./node_modules/web3-eth-accounts/lib/index.js 30:76-93处出现错误: 模块未找到:在'/home/test/gatsby/test/test/node_modules/web3->eth-accounts/lib'中无法解析'crypto'

重大变更:webpack < 5默认情况下会包含node.js核心模块的polyfill,但现在不再如此。请验证是否需要此模块并为其配置polyfill。

如果您想要包含polyfill,则需要: - 添加回退 'resolve.fallback: { "crypto": require.resolve("crypto-browserify") }' - 安装 'crypto-browserify' 如果您不想包含polyfill,则可以使用空模块,如下所示: resolve.fallback: { "crypto": false }  @ ./node_modules/web3-eth/lib/index.js 34:15-43  @ ./node_modules/web3/lib/index.js 30:10-29  @ ./src/pages/index.js 9:0-24  @ ./.cache/this_is_virtual_fs_path/$virtual/async-requires.js 21:11-23:5  @ ./.cache/app.js 17:0-52 28:0-70 30:27-40 28:0-70

在./node_modules/web3-eth-accounts/node_modules/eth-lib/lib/bytes.js 7:193-227处出现错误: 模块未找到:在'/home/test/gatsby/test/test/node_modules/web3-eth-accounts/node_modules/eth-lib/lib'中无法解析'crypto'

重大变更:webpack < 5默认情况下会包含node.js核心模块的polyfill,但现在不再如此。请验证是否需要此模块并为其配置polyfill。

如果您想要包含polyfill,则需要: - 添加回退 'resolve.fallback: { "crypto": require.resolve("crypto-browserify") }' - 安装 'crypto-browserify' 如果您不想包含polyfill,则可以使用空模块,如下所示: resolve.fallback: { "crypto": false }  @ ./node_modules/web3-eth-accounts/lib/index.js 29:12-40  @ ./node_modules/web3-eth/lib/index.js 34:15-43  @ ./node_modules/web3/lib/index.js 30:10-29  @ ./src/pages/index.js 9:0-24  @ ./.cache/this_is_virtual_fs_path/$virtual/async-requires.js 21:11-23:5  @ ./.cache/app.js 17:0-52 28:0-70 30:27-40 28:0-70

在./node_modules/web3-providers-http/lib/index.js 26:11-26出现错误 模块未找到:错误:无法在'/home/test/gatsby/test/test/node_modules/web3-providers-http/lib'中解析'http'

BREAKING CHANGE: webpack < 5默认情况下会包含node.js核心模块的polyfill。 现在不再是这种情况。验证您是否需要此模块并为其配置polyfill。

如果要包含polyfill,您需要: - 添加回退'resolve.fallback: { "http": require.resolve("stream-http") }' - 安装'stream-http' 如果不想包含polyfill,可以像这样使用一个空模块: resolve.fallback: { "http": false }  @ ./node_modules/web3-core-requestmanager/lib/index.js 46:18-48  @ ./node_modules/web3-core/lib/index.js 22:23-58  @ ./node_modules/web3/lib/index.js 29:11-31  @ ./src/pages/index.js 9:0-24  @ ./.cache/this_is_virtual_fs_path/$virtual/async-requires.js 21:11-23:5  @ ./.cache/app.js 17:0-52 28:0-70 30:27-40 28:0-70

在./node_modules/web3-providers-http/lib/index.js 27:12-28出现错误 模块未找到:错误:无法在'/home/test/gatsby/test/test/node_modules/web3-providers-http/lib'中解析'https'

BREAKING CHANGE: webpack < 5默认情况下会包含node.js核心模块的polyfill。 现在不再是这种情况。验证您是否需要此模块并为其配置polyfill。

如果要包含polyfill,您需要: - 添加回退'resolve.fallback: { "https": require.resolve("https-browserify") }' - 安装'https-browserify' 如果不想包含polyfill,可以像这样使用一个空模块: resolve.fallback: { "https": false }  @ ./node_modules/web3-core-requestmanager/lib/index.js 46:18-48  @ ./node_modules/web3-core/lib/index.js 22:23-58  @ ./node_modules/web3/lib/index.js 29:11-31  @ ./src/pages/index.js 9:0-24  @ ./.cache/this_is_virtual_fs_path/$virtual/async-requires.js 21:11-23:5  @ ./.cache/app.js 17:0-52 28:0-70 30:27-40 28:0-70

在./node_modules/xhr2-cookies/dist/xml-http-request.js 21:11-26处出现错误 模块未找到:错误:无法解析“/home/test/gatsby/test/test/node_modules/xhr2-cookies/dist”中的“http”

BREAKING CHANGE: webpack < 5默认情况下会包含node.js核心模块的polyfills。 这不再是默认情况。请验证是否需要此模块并为其配置polyfill。

如果您想包含polyfill,则需要: - 添加后备“resolve.fallback:{“http”:require.resolve(“stream-http”)}” - 安装'stream-http' 如果您不想包含polyfill,则可以使用空模块,如下所示: resolve.fallback:{“http”:false} @ ./node_modules/xhr2-cookies/dist/index.js 6:9-38 @ ./node_modules/web3-providers-http/lib/index.js 25:11-49 @ ./node_modules/web3-core-requestmanager/lib/index.js 46:18-48 @ ./node_modules/web3-core/lib/index.js 22:23-58 @ ./node_modules/web3/lib/index.js 29:11-31 @ ./src/pages/index.js 9:0-24 @ ./.cache/this_is_virtual_fs_path/$virtual/async-requires.js 21:11-23:5 @ ./.cache/app.js 17:0-52 28:0-70 30:27-40 28:0-70

在./node_modules/xhr2-cookies/dist/xml-http-request.js 22:12-28处出现错误 模块未找到:错误:无法解析“/home/test/gatsby/test/test/node_modules/xhr2-cookies/dist”中的“https”

BREAKING CHANGE: webpack < 5默认情况下会包含node.js核心模块的polyfills。 这不再是默认情况。请验证是否需要此模块并为其配置polyfill。

如果你想要包含一个 polyfill,你需要: - 添加回退 'resolve.fallback: { "https": require.resolve("https-browserify") }' - 安装 'https-browserify' 如果你不想包含一个 polyfill,你可以使用一个空模块,像这样: resolve.fallback: { "https": false }  @ ./node_modules/xhr2-cookies/dist/index.js 6:9-38  @ ./node_modules/web3-providers-http/lib/index.js 25:11-49  @ ./node_modules/web3-core-requestmanager/lib/index.js 46:18-48  @ ./node_modules/web3-core/lib/index.js 22:23-58  @ ./node_modules/web3/lib/index.js 29:11-31  @ ./src/pages/index.js 9:0-24  @ ./.cache/this_is_virtual_fs_path/$virtual/async-requires.js 21:11-23:5  @ ./.cache/app.js 17:0-52 28:0-70 30:27-40 28:0-70
ERROR in ./node_modules/xhr2-cookies/dist/xml-http-request.js 23:9-22 模块未找到:错误:无法在 '/home/test/gatsby/test/test/node_modules/xhr2-cookies/dist' 中解析 'os'
重大变化:webpack < 5 默认情况下会为 node.js 核心模块包含 polyfill。 现在不再是这种情况。请验证您是否需要此模块,并为其配置 polyfill。
如果你想要包含一个 polyfill,你需要: - 添加回退 'resolve.fallback: { "os": require.resolve("os-browserify/browser") }' - 安装 'os-browserify' 如果你不想包含一个 polyfill,你可以使用一个空模块,像这样: resolve.fallback: { "os": false }  @ ./node_modules/xhr2-cookies/dist/index.js 6:9-38  @ ./node_modules/web3-providers-http/lib/index.js 25:11-49  @ ./node_modules/web3-core-requestmanager/lib/index.js 46:18-48  @ ./node_modules/web3-core/lib/index.js 22:23-58  @ ./node_modules/web3/lib/index.js 29:11-31  @ ./src/pages/index.js 9:0-24  @ ./.cache/this_is_virtual_fs_path/$virtual/async-requires.js 21:11-23:5  @ ./.cache/app.js 17:0-52 28:0-70 30:27-40 28:0-70
webpack 编译出现了 10 个错误
我已尝试手动安装这些模块、将它们添加到 package.json 等等。但是什么都不起作用。
你能帮我吗?
5个回答

7

这对我有用。将以下内容添加到您的gatsby-node.js配置文件中:

const webpack = require("webpack");

exports.onCreateWebpackConfig = ({ actions }) => {
    actions.setWebpackConfig({
        plugins: [
            new webpack.ProvidePlugin({
                Buffer: [require.resolve("buffer/"), "Buffer"],
            }),
        ],
        resolve: {
            fallback: {
                "crypto": false,
                "stream": require.resolve("stream-browserify"),
                "assert": false,
                "util": false,
                "http": false,
                "https": false,
                "os": false
            },
        },
    })
}

1
谢谢。我花了2个小时寻找这个答案。这是最好的解决方案,因为该问题适用于web3-provider包。 - Christian Lacdael
我也遇到了同样的错误,但是我在使用Vue.js,你能帮我吗? - Crazy

7
很遗憾,Web3堆栈的大部分都严重依赖于window、browser和外部加密依赖项,这些依赖在服务器端不可用。这不仅是Gatsby的问题,也是其他SSR和静态站点生成器(例如Next.js)的问题。
不过还有一些解决方法。请参见在Gatsby上使用仅客户端的包
  1. 使用不同的库或方法

  2. 通过CDN添加客户端包

  3. 使用loadable-components加载客户端依赖组件

  4. 仅在客户端上使用React.lazy和Suspense

根据您的要求,选项#1可能不适用。我在使用ethers而不是web3时取得了更好的成功效果。但是您可能会在某些时候遇到类似的问题。
结合选项#2和#3/4将是前进的道路。 首先,删除引起问题的软件包(web3),然后从gatsby-browser.js中加载它们,或者在使用它的页面/组件上使用react-helmet
const addScript = url => {
  const script = document.createElement("script")
  script.src = url
  script.async = true
  document.body.appendChild(script)
}

export const onClientEntry = () => {
  window.onload = () => {
    addScript("https://cdn.jsdelivr.net/npm/web3@latest/dist/web3.min.js")
  }
}

react-helmet

<Helmet>
    <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/web3@latest/dist/web3.min.js" />
</Helmet>

你现在应该能够使用web3了。请确保检查是否在浏览器中运行,可以使用typeof window !== "undefined"。以下是完整的代码示例:

import React from 'react'
import { Helmet } from "react-helmet"

export default function Web3() {
    const [blockNr, setBlockNr] = React.useState()
    const isBrowser = typeof window !== "undefined"

    async function getBlockNumber() {
        console.log('Init web3')
        const web3 = new window.Web3('https://cloudflare-eth.com')
        const currentBlockNumber = await web3.eth.getBlockNumber()
        setBlockNr(currentBlockNumber)        
    }

    return (
        <div>
            {/* Can use either react-helmet or include the script from gatsby-browser */}
            <Helmet>
                <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/web3@latest/dist/web3.min.js" />
            </Helmet>
            {isBrowser && 
                <div>
                    <p>Running in browser..</p>
                    <button onClick={getBlockNumber}>Get Block #</button>
                </div>
            }
            
            {blockNr && <span>{blockNr}</span>}
        </div>
    )
}

您可能仍然希望使用延迟加载或者使用loadable-components。例如:

const LazyWeb3BlockNr = React.lazy(() =>
  import("../components/Web3BlockNr")
)

而在你的页面中

<div>
    {typeof window !== "undefined" && 
        <React.Suspense fallback={<div />}>
            <LazyWeb3BlockNr />
        </React.Suspense>
    }
</div>

https://github.com/wslyvh/web3-gatsby上可以找到完整的代码示例。


1
这似乎是通过一些试验得出的结论,但并不是必要的。我之前在另一个项目中也使用了Walletconnect,但同样需要通过CDN加载。与上述描述类似的方法。 - wslyvh

3

请执行以下操作

npm install --save-dev react-app-rewired crypto-browserify stream-browserify assert stream-http https-browserify os-browserify url buffer process

在你的根目录下创建一个 config-overrides.js,并添加以下内容:
const 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")
    })
    config.resolve.fallback = fallback;
    config.plugins = (config.plugins || []).concat([
        new webpack.ProvidePlugin({
            process: 'process/browser',
            Buffer: ['buffer', 'Buffer']
        })
    ])
    return config;
}

现在将你的package.json中的scripts:更改为:

"scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-scripts eject"
},

终于,我在浪费许多时间后成功了!


1
webpack 5 issue documentation
https://web3auth.io/docs/troubleshooting/webpack-issues

steps:-
1 run this command inside react folder 
>>npm install --save-dev react-app-rewired crypto-browserify stream-browserify assert stream-http https-browserify os-browserify url buffer process

2.Create config-overrides.js in the root of your project folder with the content:
 
content of this page
const 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"),
  });
  config.resolve.fallback = fallback;
  config.plugins = (config.plugins || []).concat([
    new webpack.ProvidePlugin({
      process: "process/browser",
      Buffer: ["buffer", "Buffer"],
    }),
  ]);
  return config;
};

3>Within package.json of react.js change the scripts field for start, build and test. Instead of react-scripts replace it with react-app-rewired

"scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-scripts eject"
},

4>>
The missing Nodejs polyfill should be included now and your app should be functional with web3.

If you want to hide the warnings created by the console:
In config-overrides.js within the override function, add

     config. ignoreWarnings

  = [/Failed to parse source map/];

0

如果您不想手动安装每个单独的包,可以使用node-polyfill-webpack-plugin包。链接的README有更多关于如何自定义插件的示例,但您只需像这样添加即可:

const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');

module.exports = {
    // Other rules...
    plugins: [
        new NodePolyfillPlugin()
    ]
};

添加到你的webpack.config.js文件中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接