【问题标题】:Cannot add web3 to React project无法将 web3 添加到 React 项目
【发布时间】:2021-07-01 07:29:25
【问题描述】:

我正在尝试将 Web3 添加到 React 项目。 我用

初始化了一个新项目
gatsby new

然后,我已经安装了 web3

npm install --save web3

当我在 index.js 中包含 web3 时

import Web3 from 'web3'

如果我打电话

gatsby develop

我有一些奇怪的错误:

./node_modules/eth-lib/lib/bytes.js 9:193-227 中的错误 找不到模块:错误:无法解析“/home/test/gatsby/test/test/node_modules/eth-lib/lib”中的“crypto”

重大变化:webpack

如果你想包含一个 polyfill,你需要: - 添加一个后备 'resolve.fallback: { "crypto": require.resolve("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

./node_modules/ethereumjs-util/dist/account.js 中的错误 4:13-30 未找到模块:错误:无法解析 >'/home/test/gatsby/test/test/node_modules/ethereumjs-util/dist'中的“断言”

重大变化:webpack

如果你想包含一个 polyfill,你需要: - 添加一个后备 'resolve.fallback: { "assert": require.resolve("assert/") }' - 安装“断言” 如果您不想包含 polyfill,则可以使用这样的空模块: 解决.fallback:{“断言”:假} @ ./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 未找到模块:错误:无法解析 >'/home/test/gatsby/test/test/node_modules/ethereumjs-util/dist'中的“断言”

重大变化:webpack

如果你想包含一个 polyfill,你需要: - 添加一个后备 'resolve.fallback: { "assert": require.resolve("assert/") }' - 安装“断言” 如果您不想包含 polyfill,则可以使用这样的空模块: 解决.fallback:{“断言”:假} @ ./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

如果你想包含一个 polyfill,你需要: - 添加一个后备 'resolve.fallback: { "crypto": require.resolve("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

如果你想包含一个 polyfill,你需要: - 添加一个后备 'resolve.fallback: { "crypto": require.resolve("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”

重大变化:webpack

如果你想包含一个 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”

重大变化:webpack

如果你想包含一个 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”

重大变化:webpack

如果你想包含一个 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”

重大变化:webpack

如果你想包含一个 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

./node_modules/xhr2-cookies/dist/xml-http-request.js 23:9-22 中的错误 找不到模块:错误:无法解析“/home/test/gatsby/test/test/node_modules/xhr2-cookies/dist”中的“os”

重大变化:webpack

如果你想包含一个 polyfill,你需要: - 添加一个后备 'resolve.fallback: { "os": require.resolve("os-browserify/browser") }' - 安装“操作系统浏览器” 如果您不想包含 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 等。但没有任何效果。 你能帮帮我吗?

谢谢

【问题讨论】:

  • 您找到解决方案了吗?尝试将 web3Modal 安装到 Gatsby 项目中,结果相似。
  • 您好,我尝试了很多东西,但没有找到解决方案。我放弃了 gatsby,直接用 Ethers.js 做了一个静态网站。
  • 我已经能够让事情正常进行。在下面发布答案以供参考。虽然,放弃 Gatsby (SSR) 可能是更好的解决方案

标签: reactjs web3


【解决方案1】:

不幸的是,大多数 Web3 堆栈严重依赖于窗口、浏览器和外部加密依赖项,这些依赖项在服务器端不可用。这不仅仅是 Gatsby 的问题,其他 SSR 和静态站点生成器(例如 Next.js)也是如此。

虽然有一些解决方法。见Using Client-Side Only Packages on Gatsby

  1. 使用不同的库或方法

  2. 通过 CDN 添加客户端包

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

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

根据您的要求,#1 可能不是一个选项。我使用 ethers 而不是 web3 取得了更好的成功。但是您可能会在某些时候遇到与其他软件包类似的问题。

#2 和 3/4 的组合将是可行的方法。 首先,删除导致问题的包 (web3),然后从 gatsby-browser.js 或在使用它的页面/组件上使用 react-helmet 加载它们。

gatsby-browser.js

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")
  }
}

反应头盔

<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>
    )
}

您可能仍想加载 Lazy 或使用可加载组件。例如

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

【讨论】:

  • 我注意到您将@walletconnect/web3-provider 添加到您的package.json,但实际上并没有使用它。你知道如何在钱包组件中延迟加载它吗?
  • 这似乎是对它的一点尝试,但应该没有必要。我确实在另一个项目中使用了 Walletconnect,但也必须通过 CDN 加载它。与上述类似的方法。
【解决方案2】:

这对我有用。将以下内容添加到您的 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
            },
        },
    })
}

【讨论】:

  • 谢谢。我花了 2 个小时寻找这个答案。这是最好的解决方案,因为该问题适用于 web3-provider 包。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-20
  • 2021-01-26
相关资源
最近更新 更多