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
相关产品推荐
相关产品推荐

