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

Supabase能否在非Beta版NextJS中兼容SSR/SSG/CSR?

在非Beta版NextJS中实现Supabase同时支持服务端与客户端渲染

答案是肯定的,无需依赖NextJS 13 Beta版就能实现。核心思路是避免全局包裹客户端认证上下文,结合服务端会话预取与局部上下文包裹,既保留SSR/SSG的能力,又简化客户端组件的认证逻辑。

方案1:拆分上下文包裹范围,仅在需要的页面/组件局部使用

不要在_app.js中用SessionContextProvider包裹整个应用(这会强制全应用变为CSR),而是只在需要客户端交互的认证页面/组件外层单独包裹。服务端渲染的页面则通过getServerSideProps/getStaticProps直接获取会话,无需依赖客户端上下文。

示例代码:

  1. 服务端渲染的认证页面(带局部上下文)
import { SessionContextProvider } from '@supabase/auth-helpers-react'
import { createClientComponentClient, createServerComponentClient } from '@supabase/auth-helpers-nextjs'
import UserProfile from '../components/UserProfile'

export default function Dashboard({ initialSession }) {
  // 创建客户端Supabase实例
  const supabase = createClientComponentClient()

  return (
    // 仅在当前页面范围内包裹上下文
    <SessionContextProvider supabaseClient={supabase} initialSession={initialSession}>
      <UserProfile />
    </SessionContextProvider>
  )
}

// 服务端预取会话,传给页面做初始化
export async function getServerSideProps(context) {
  const supabase = createServerComponentClient(context)
  const { data: { session } } = await supabase.auth.getSession()

  return {
    props: { initialSession: session }
  }
}
  1. 纯静态/服务端渲染的公共页面
export default function Home({ posts }) {
  return (
    <div>
      <h1>首页</h1>
      <ul>
        {posts.map(post => <li key={post.id}>{post.title}</li>)}
      </ul>
    </div>
  )
}

// 服务端预取公共数据,生成静态页面
export async function getStaticProps() {
  const supabase = createServerComponentClient({})
  const { data: posts } = await supabase.from('posts').select('title, id')

  return {
    props: { posts },
    revalidate: 60 // 可选:启用增量静态再生
  }
}
  1. 客户端组件通过上下文获取会话
import { useSession } from '@supabase/auth-helpers-react'

export default function UserProfile() {
  const { session } = useSession()

  if (!session) {
    return <p>请先登录</p>
  }

  return <div>欢迎回来,{session.user.email}</div>
}

方案2:封装高阶组件(HOC)简化认证逻辑

如果多个页面需要认证,可以封装一个withAuth高阶组件,统一处理服务端会话预取和上下文包裹,减少重复代码。

示例代码:

import { SessionContextProvider } from '@supabase/auth-helpers-react'
import { createClientComponentClient, createServerComponentClient } from '@supabase/auth-helpers-nextjs'

export function withAuth(Component) {
  return function AuthenticatedComponent({ initialSession, ...props }) {
    const supabase = createClientComponentClient()
    return (
      <SessionContextProvider supabaseClient={supabase} initialSession={initialSession}>
        <Component {...props} />
      </SessionContextProvider>
    )
  }
}

// 统一处理服务端会话获取
export async function getAuthServerSideProps(context) {
  const supabase = createServerComponentClient(context)
  const { data: { session } } = await supabase.auth.getSession()

  // 如果未登录,重定向到登录页
  if (!session) {
    return {
      redirect: {
        destination: '/login',
        permanent: false
      }
    }
  }

  return {
    props: { initialSession: session }
  }
}

使用方式:

import { withAuth, getAuthServerSideProps } from '../hocs/withAuth'
import UserSettings from '../components/UserSettings'

function SettingsPage() {
  return <UserSettings />
}

export default withAuth(SettingsPage)
export const getServerSideProps = getAuthServerSideProps

关键注意事项

  • 服务端客户端创建:在getServerSideProps/getStaticProps中必须传递context给createServerComponentClient,确保会话与请求关联。
  • 会话同步:通过服务端预取的initialSession初始化客户端上下文,避免客户端重新发起认证请求,确保前后端会话一致。
  • 避免全局CSR:不要在_app.js中全局使用useState或客户端Supabase实例,否则会强制整个应用变为客户端渲染。

内容的提问来源于stack exchange,提问作者Victor M

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 05:30:48