
本文详解 next.js 中 `getstaticprops` + `getstaticpaths` 页面无法生成静态 html 源码的根本原因,重点修复 `_app.js` 中的客户端渲染逻辑导致 ssr/ssg 失效的问题,并提供可落地的 seo 友好配置。
你遇到的问题——页面在浏览器中渲染正常,但查看网页源代码(View Page Source)为空白或仅含
,且禁用 javaScript 后页面完全不显示——这明确表明:Next.js 并未真正执行静态生成(SSG),而是退化为客户端渲染(CSR)。根本原因在于 _app.js 中的条件渲染逻辑破坏了服务端渲染流程。
? 问题定位:_app.js 中的致命判断
原始代码中这一行是症结所在:
return ( typeof window !== "undefined" && ( // ❌ 服务端 `window` 为 undefined → 返回 false → 渲染空内容 <> > ) );
在服务端渲染(SSR)或静态生成(SSG)阶段,node.js 环境下 typeof window === “undefined” 恒为 true,因此整个 JSX 表达式求值为 false,导致服务端返回空响应(无 html 内容)。浏览器端 JS 加载后才执行渲染,这就是“源码为空、禁 JS 不显示”的直接原因。
✅ 正确解法:移除服务端阻断逻辑
修改后的 _app.js 必须确保服务端和客户端均能正常渲染组件树:
import react from "react"; import App from "next/app"; import TagManager from "react-gtm-module"; import NextNProgress from "../components/NextNProgress"; import "bootstrap/dist/css/bootstrap.css"; import "../scss/index.scss"; const tagManagerArgs = { gtmId: "########", }; class MyApp extends App { static async getInitialProps({ Component, ctx }) { let pageProps = {}; if (Component.getInitialProps) { pageProps = await Component.getInitialProps(ctx); } return { pageProps }; } componentDidMount() { TagManager.initialize(tagManagerArgs); } render() { const { Component, pageProps } = this.props; return ( <> {/* 进度条组件需支持 SSR,建议检查其内部是否含 window/document 依赖 */} > ); } } export default MyApp;
✅ 关键改动:
- 彻底移除 typeof window !== “undefined” 条件包裹,保证服务端可渲染完整 dom 树;
- 保留 componentDidMount 中的 GTM 初始化(仅在客户端执行,安全);
- NextNProgress 组件需确认其 SSR 兼容性(避免在服务端调用 window 或 document)。
? 验证是否真正 SSG 成功
-
构建并预览静态产物:
next build && next export # 若使用 `next export` # 或直接运行:next build && next start -
检查输出 HTML:
- 访问 http://localhost:3000 → 右键「查看网页源代码」→ 应看到完整的、包含实际内容的 HTML(非仅
);
- 在 chrome DevTools 的 Network 选项卡中,刷新页面,查看 index.html 响应体,确认内含预渲染的文本、标题、结构化数据等。
禁用 javascript 测试:
- Chrome 设置 → Privacy and Security → Site Settings → Content → JavaScript → Block;
- 重启页面 → 页面仍应完整显示(证明服务端已生成 HTML)。
⚠️ 注意事项与增强建议
-
安全性:若该组件内部依赖 window.addEventListener 或 document.querySelector,需改造为仅在客户端挂载: // 推荐写法:延迟客户端组件挂载 import { useEffect, useState } from 'react'; export default function SafeNProgress() { const [mounted, setMounted] = useState(false); useEffect(() => setMounted(true), []); return mounted ?: null; } -
_document.js 优化:你当前的 _document.js 是标准写法,但注意:
- 的 crossOrigin=”anomynous” 拼写错误,应为 “anonymous”;
- 所有 和 标签必须放在 内,你已正确实现。
-
seo 强化补充(推荐): 在页面组件中使用 next/head 注入动态 meta:
import Head from 'next/head'; export default function ProductPage({ product }) { return ( <>{product.name} | DMI Store > ); }{product.name}
{product.description}
✅ 总结
Next.js 的 SSG 能力高度依赖服务端可执行的纯 React 渲染流程。任何在 _app.js 或页面中对 window 的同步依赖、条件屏蔽,都会导致静态 HTML 生成失败。修复核心永远是:确保服务端能产出完整 HTML 字符串,客户端仅负责增强交互。按本文方案调整后,你的产品页将真正具备搜索引擎可抓取、无障碍可访问、JS 禁用仍可用的生产级 SEO 表现。
- 访问 http://localhost:3000 → 右键「查看网页源代码」→ 应看到完整的、包含实际内容的 HTML(非仅