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

使用Base Web时Next.js报ReferenceError: document is not defined求助

问题:Next.js App Router中ReferenceError: document is not defined(StyletronClient相关)
  • 试过很多关于error ReferenceError: document is not defined的解决方案,但都不管用。之前这个问题被标记为重复,但旧方案无效,而且相关帖子已经是3年9个月前的了,React、Next.js以及SSR和客户端渲染的语法都变了很多。
  • 终端报错信息:
- error node_modules/styletron-engine-atomic/dist-node-cjs/client/client.js (167:0) @ new StyletronClient
- error ReferenceError: document is not defined
    at eval (./src/app/layout.js:15:16)
    at (sc_client)/./src/app/layout.js (/Users/anthonyweston/Sites/fogg/.next/server/app/page.js:2296:1)
    at __webpack_require__ (/Users/me/Sites/nextjs-baseweb/.next/server/webpack-runtime.js:33:42)
null
  • 看到其他问题提到next/dynamic,但感觉不是我的解决方案?相关代码可复现问题。

解决方案

方法1:拆分客户端组件初始化StyletronClient

Next.js 13+ App Router默认组件是服务器组件,没法访问浏览器的document对象。所以要把Styletron的初始化放到客户端组件里:

  1. 新建一个客户端组件(比如StyletronProviderClient.js),顶部加上"use client"声明;
  2. 在这个组件里初始化StyletronClient并提供上下文;
  3. 在layout.js里导入使用这个组件。

代码示例:

// src/components/StyletronProviderClient.js
"use client";

import { StyletronProvider } from "styletron-react";
import { StyletronClient } from "styletron-engine-atomic";

const engine = new StyletronClient();

export default function StyletronProviderClient({ children }) {
  return <StyletronProvider value={engine}>{children}</StyletronProvider>;
}

然后修改layout.js:

// src/app/layout.js
import StyletronProviderClient from "@/components/StyletronProviderClient";

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        <StyletronProviderClient>{children}</StyletronProviderClient>
      </body>
    </html>
  );
}

方法2:在useEffect中延迟初始化

如果不想拆分组件,可以给layout.js加上"use client",然后用useEffect延迟创建Styletron实例,避免服务器渲染时执行:

// src/app/layout.js
"use client";

import { StyletronProvider } from "styletron-react";
import { StyletronClient } from "styletron-engine-atomic";
import { useEffect, useState } from "react";

export default function RootLayout({ children }) {
  const [engine, setEngine] = useState(null);

  useEffect(() => {
    setEngine(new StyletronClient());
  }, []);

  if (!engine) return null; // 也可以换成加载中组件

  return (
    <html lang="en">
      <body>
        <StyletronProvider value={engine}>{children}</StyletronProvider>
      </body>
    </html>
  );
}

关于next/dynamic的说明

next/dynamic主要是旧Pages Router里用来动态导入并禁用SSR的方式,在App Router里更推荐用"use client"指令来明确区分客户端组件,这是Next.js新架构的标准做法,比next/dynamic更适配当前的路由体系。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 11:47:41