You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NextJS中CoinbaseWalletSDK服务端渲染报错求助

问题根源

你当前的核心问题是:getServerSideProps 在服务器端运行,而你在其中导入的 coinbase 服务模块,在加载时就直接执行了 new CoinbaseWalletSDK()——服务器环境没有 window 和 localStorage,因此必然抛出 ReferenceError。动态导入在这里无效,因为模块顶层的初始化代码依然会在服务器端执行。

解决方案

需要将 Coinbase Wallet SDK 的初始化逻辑完全限制在客户端环境执行,同时重构服务代码,避免模块加载时自动初始化。

步骤1:重构 Coinbase 服务代码

将初始化逻辑封装为函数,且仅在客户端环境下执行:

// components/services/coinbase.ts
import CoinbaseWalletSDK from '@coinbase/wallet-sdk'
import Web3 from 'web3'

const APP_NAME = 'Practice App'
const APP_LOGO_URL = process.env.WEBSITE_URL + '/logo.png'
const DEFAULT_ETH_JSONRPC_URL = 'https://mainnet.infura.io/v3/' + process.env.INFURA_PROJECT_ID
const DEFAULT_CHAIN_ID = 1

// 仅在客户端环境执行初始化
const isClient = typeof window !== 'undefined'

export const initCoinbaseWallet = () => {
  if (!isClient) {
    throw new Error('Coinbase Wallet SDK 只能在客户端初始化')
  }

  const coinbaseWallet = new CoinbaseWalletSDK({
    appName: APP_NAME,
    appLogoUrl: APP_LOGO_URL,
    darkMode: false
  })

  const coinbaseEth = coinbaseWallet.makeWeb3Provider(DEFAULT_ETH_JSONRPC_URL, DEFAULT_CHAIN_ID)
  const web3 = new Web3(coinbaseEth as any)

  return { coinbaseWallet, coinbaseEth, web3 }
}

步骤2:修改页面的 getServerSideProps

移除其中与 Coinbase 相关的导入和逻辑,仅保留项目数据处理:

export async function getServerSideProps({
  params,
}: {
  params: { project_id: string };
}) {

  const project_id = params.project_id;

  let project: any = fakeProjects[0];
  if (project_id && typeof project_id === 'string' && !isNaN(parseInt(project_id))) {
    const id = project_id;
    project = fakeProjects.find(p => p.id === parseInt(id));

    let item = await getNFTStatsByProjectId(parseInt(project_id));
    if (project && item && item['nftTotal'] && item['nftSold']) {
      if (item.nftSold > item.nftTotal) {
        item.nftSold = item.nftTotal;
      }
      project.nftTotal = item.nftTotal;
      project.nftSold = item.nftSold;
    }
  }

  return {
    props: { 
      project: project
    },
  };
}

步骤3:在页面组件中客户端初始化钱包

使用 useEffect(仅在客户端执行)来初始化 SDK,或者用 Next.js 的动态导入禁用 SSR:

方案A:直接在页面组件中用 useEffect

import { useEffect, useState } from 'react'
import { initCoinbaseWallet } from '../../components/services/coinbase'

export default function ProjectPage({ project }: { project: any }) {
  const [coinbaseEth, setCoinbaseEth] = useState<any>(null)

  useEffect(() => {
    const initWallet = async () => {
      try {
        const { coinbaseEth } = initCoinbaseWallet()
        setCoinbaseEth(coinbaseEth)
      } catch (err) {
        console.error('初始化 Coinbase 钱包失败:', err)
      }
    }

    initWallet()
  }, [])

  return (
    <div>
      <h1>{project.name}</h1>
      {coinbaseEth ? (
        <button onClick={() => coinbaseEth.enable()}>连接 Coinbase 钱包</button>
      ) : (
        <p>加载钱包中...</p>
      )}
    </div>
  )
}

方案B:动态导入钱包组件(更优雅)

创建独立的钱包组件:

// components/CoinbaseWalletButton.tsx
import { useEffect, useState } from 'react'
import { initCoinbaseWallet } from './services/coinbase'

export default function CoinbaseWalletButton() {
  const [coinbaseEth, setCoinbaseEth] = useState<any>(null)

  useEffect(() => {
    const { coinbaseEth } = initCoinbaseWallet()
    setCoinbaseEth(coinbaseEth)
  }, [])

  const handleConnect = async () => {
    if (coinbaseEth) {
      try {
        await coinbaseEth.enable()
        console.log('钱包已连接')
      } catch (err) {
        console.error('连接失败:', err)
      }
    }
  }

  return (
    <button onClick={handleConnect} disabled={!coinbaseEth}>
      {coinbaseEth ? '连接 Coinbase 钱包' : '加载中...'}
    </button>
  )
}

在页面组件中动态导入该组件并禁用 SSR:

import dynamic from 'next/dynamic'

const CoinbaseWalletButton = dynamic(() => import('../../components/CoinbaseWalletButton'), {
  ssr: false,
  loading: () => <p>加载钱包按钮中...</p>
})

export default function ProjectPage({ project }: { project: any }) {
  return (
    <div>
      <h1>{project.name}</h1>
      <CoinbaseWalletButton />
    </div>
  )
}
关键注意事项
  • 任何依赖 window、localStorage 的代码,都不能在服务器端执行(包括模块顶层代码、getServerSideProps、getStaticProps)
  • 通过 typeof window !== 'undefined' 可以准确判断是否处于客户端环境
  • 动态导入时设置 ssr: false,会强制组件仅在客户端加载和渲染

内容的提问来源于stack exchange,提问作者Terry Windwalker

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 05:33:27