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

Next.js集成gapi-script报错:ReferenceError: window is not defined

Next.js集成gapi-script时反复出现"ReferenceError: window is not defined"服务端错误排查

错误详情

Server Error
ReferenceError: window is not defined
This error happened while generating the page. Any console logs will be displayed in the terminal window.

调用栈:

eval
node_modules/gapi-script/gapiScript.js (1:9)
./node_modules/gapi-script/gapiScript.js
file:[...]/.next/server/pages/[...]/[id].js (98:1)
webpack_require
file:/[...]/.next/server/webpack-runtime.js (33:42)

相关代码

import { useEffect } from 'react';
import Head from 'next/head';
import styles from '../../../styles/Home.module.css';
import { GoogleLoginButton } from '../../../components';
import { gapi } from 'gapi-script';

export async function getServerSideProps(context: any) {
  const res = await fetch(
    `http://localhost:3000/api/...`,
  );
  const data = await res.json();

  return { props: { data } };
}

const GAPI_CONFIG = {
  apiKey: process.env.GOOGLE_API_KEY,
  clientId: process.env.CLIENT_ID,
  scope: process.env.GOOGLE_SCOPE,
};

export default function NblOneTeam({ data }: any) {
  useEffect(() => {
    function start() {
      gapi.client.init(GAPI_CONFIG);
    }
    gapi.load('client:auth2', start);
  });

  return (
    <div className={styles.container}>
      <Head>
        <title>NBL1 Scout Generator</title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main className={styles.main}>
        <h1>Hi NBL1 Teams</h1>
        <GoogleLoginButton />
        {data.map((player: any) => {
          return <h2>{player.name}</h2>;
        })}
      </main>
    </div>
  );
}

已尝试方案

参考了Next.js中"window is not defined"相关问题的解决方案,但问题仍未解决。

问题原因

Next.js采用服务端渲染(SSR)机制,代码会先在服务端执行一遍。当前通过import { gapi } from 'gapi-script'进行静态导入,会导致gapi-script库在服务端被加载执行,而该库源码直接依赖浏览器环境的window对象,服务端不存在window,因此抛出ReferenceError。

解决方案

方案1:在客户端动态导入gapi-script

删除静态导入语句,在useEffect中动态导入gapi,确保代码仅在浏览器客户端执行:

// 移除静态导入:import { gapi } from 'gapi-script';

export default function NblOneTeam({ data }: any) {
  useEffect(() => {
    const initGapi = async () => {
      const { gapi } = await import('gapi-script');
      function start() {
        gapi.client.init(GAPI_CONFIG);
      }
      gapi.load('client:auth2', start);
    };
    initGapi();
  }, []); // 空依赖数组确保仅在组件挂载时执行一次

  // 其余代码不变
}

方案2:条件导入gapi-script

通过判断window是否存在,仅在客户端环境加载gapi:

// 替换静态导入为条件导入
let gapi;
if (typeof window !== 'undefined') {
  gapi = require('gapi-script').gapi;
}

export default function NblOneTeam({ data }: any) {
  useEffect(() => {
    if (!gapi) return; // 确保gapi已加载
    function start() {
      gapi.client.init(GAPI_CONFIG);
    }
    gapi.load('client:auth2', start);
  }, []);

  // 其余代码不变
}

方案3:通过脚本标签在客户端加载gapi

直接在Head中添加Google API的脚本标签,避免通过npm包导入:

export default function NblOneTeam({ data }: any) {
  const initGapi = () => {
    window.gapi.client.init(GAPI_CONFIG);
  };

  return (
    <div className={styles.container}>
      <Head>
        <title>NBL1 Scout Generator</title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
        {/* 加载Google API脚本,加载完成后初始化 */}
        <script 
          src="https://apis.google.com/js/api.js" 
          onLoad={initGapi}
          async
        />
      </Head>

      {/* 其余代码不变 */}
    </div>
  );
}

内容的提问来源于stack exchange,提问作者Matthew Dwyer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 05:55:25