Next.js中如何让handleSignInWithGoogle函数全局可用?
在Next.js中实现Supabase Google预构建OAuth的全局回调函数
问题原因
你在layout.tsx的JSX里直接写<script>标签导致语法错误,因为Next.js的App Router中,JSX内的脚本需要用next/script组件适配,且直接定义全局函数的方式要适配客户端环境,同时需将函数挂载到window对象上。
正确实现方式
方法1:使用next/script组件(推荐,适配App Router)
在layout.tsx中导入next/script,通过它注入全局函数,同时确保Supabase客户端在客户端环境初始化:
import Script from 'next/script'; export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="en"> <body> {/* 注入全局回调函数 */} <Script id="google-oauth-callback" strategy="afterInteractive"> {` async function handleSignInWithGoogle(response) { // 调用全局挂载的Supabase客户端 const { data, error } = await window.supabase.auth.signInWithIdToken({ provider: 'google', token: response.credential, }); if (error) console.error('登录失败:', error); } `} </Script> {/* 全局初始化Supabase客户端 */} <Script id="supabase-client" strategy="beforeInteractive"> {` import { createClient } from '@supabase/supabase-js'; window.supabase = createClient('你的SUPABASE_URL', '你的SUPABASE_ANON_KEY'); `} </Script> {children} </body> </html> ); }
方法2:在客户端组件中挂载函数到window
创建专门的客户端组件(如GoogleAuthCallback.tsx),在组件内将函数挂载到window对象:
// app/components/GoogleAuthCallback.tsx 'use client'; import { useEffect } from 'react'; import { createClientComponentClient } from '@supabase/auth-helpers-nextjs'; export default function GoogleAuthCallback() { useEffect(() => { // 挂载到window全局作用域 window.handleSignInWithGoogle = async (response: any) => { const supabase = createClientComponentClient(); const { data, error } = await supabase.auth.signInWithIdToken({ provider: 'google', token: response.credential, }); if (error) console.error('登录出错:', error); }; // 组件卸载时清理全局函数 return () => { delete window.handleSignInWithGoogle; }; }, []); return null; }
随后在layout.tsx中引入该组件:
import GoogleAuthCallback from './components/GoogleAuthCallback'; export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="en"> <body> <GoogleAuthCallback /> {children} </body> </html> ); }
额外注意事项
- 必须确保Supabase客户端在客户端环境初始化,不能在服务端组件中直接调用
signInWithIdToken - 使用TypeScript时,需扩展
Window接口避免类型报错:
// app/types/global.d.ts declare global { interface Window { supabase: import('@supabase/supabase-js').SupabaseClient; handleSignInWithGoogle: (response: any) => Promise<void>; } } export {};
内容的提问来源于stack exchange,提问作者Phil Lucks
相关产品推荐
相关产品推荐

