Next.js如何避免SSG静态页先加载、子域名判定前的页面闪烁问题
问题解答
基础结论
getStaticProps是构建阶段运行的函数,无法获取用户请求时的URL、hostname、子域名等动态请求数据,所以你没法在这个函数里拿到subdomain做判断。- 你遇到的闪烁根本原因是:SSG生成的静态页默认嵌入的是主页面内容,页面到客户端后Hydration完成才会执行
getSubdomain()判断子域名切换内容,中间的时间差就导致了主页面一闪而过的问题。
解决闪烁的可选方案
方案1:使用Middleware重写路径(推荐,保留SSG优势)
Next.js的Middleware运行在请求到达静态资源之前,能拿到请求的完整host信息,你可以根据子域名重写请求路径,完全避免客户端切换逻辑:
- 项目根目录新增
middleware.ts:
import { NextResponse } from 'next/server' import type { NextRequest } from 'next/server' export function middleware(request: NextRequest) { const hostname = request.headers.get('host') || '' // 替换为你的主域名,可自行适配多环境、www前缀等逻辑 const subdomain = hostname.replace('.hostname.com', '').replace('www.', '') // 存在有效子域名时,重写到对应子域名页面路径,浏览器地址栏不会变化 if (subdomain && subdomain !== '') { return NextResponse.rewrite(new URL(`/${subdomain}`, request.url)) } return NextResponse.next() } // 配置只匹配首页请求 export const config = { matcher: '/', }
- 新增
pages/[subdomain]/index.tsx页面,通过getStaticPaths预生成所有企业的静态页面,或者开启fallback: 'blocking'用ISR增量生成,访问时直接返回对应子域名的静态内容,完全没有闪烁。
方案2:改用SSR(实现最简单)
如果不需要纯静态的SSG优势,直接把getStaticProps替换为getServerSideProps,服务端请求时直接判断子域名,返回对应内容:
export const getServerSideProps: GetServerSideProps = async (context) => { const { req } = context const hostname = req.headers.host || '' const subdomain = hostname.replace('.hostname.com', '').replace('www.', '') // 根据子域名加载对应内容,主域名加载home.md const content = await import(`../content/pages/${subdomain || 'home'}.md`); return { props: { content: content.default, subdomain } }; };
组件直接用props传入的subdomain做判断即可,首屏返回的就是正确内容,不会有切换闪烁。
方案3:客户端降级方案(不推荐)
如果一定要保留现有SSG逻辑,可以在组件初始渲染时先展示骨架屏/空白,等客户端判断完子域名再渲染对应内容:
const HomePage: NextPage<Props> = ({ content }) => { const { attributes } = content; const [isHydrated, setIsHydrated] = useState(false) const subdomain = getSubdomain(); useEffect(() => { setIsHydrated(true) }, []) if (!isHydrated) return <div className="h-screen w-full bg-white"></div> // 骨架屏可自行替换 return ( <> <SEO /> <div className="m-auto max-w-7xl"> {subdomain ? ( <SubdomainDataComponent subdomain={subdomain} /> ) : ( <MainPage /> )} </div> </> ); };
内容的提问来源于stack exchange,提问作者Anton Karatkevich
相关产品推荐
相关产品推荐

