在Next.js中使用ketcher-react遇window未定义错误求解决
在Next.js中集成ketcher-react解决"window is not defined"错误的方案
问题根源
ketcher-react和ketcher-standalone的部分代码依赖浏览器环境的window对象,即便你用了dynamic({ ssr: false })导入组件,模块顶层的初始化代码(比如实例化StandaloneStructServiceProvider)仍会在SSR阶段被执行,这就是报错的核心原因。
解决方案一:将依赖浏览器的逻辑移到客户端生命周期中
把模块导入和初始化逻辑放在useEffect里,确保只在浏览器环境执行:
修改KetcherEditorReact.tsx:
import { useEffect, useState } from "react"; import "ketcher-react/dist/index.css"; export default function KetcherEditorReact() { const [Editor, setEditor] = useState<React.ComponentType<any> | null>(null); const [structService, setStructService] = useState<any>(null); useEffect(() => { const initKetcher = async () => { // 动态导入依赖,避免SSR解析时触发window调用 const { StandaloneStructServiceProvider } = await import("ketcher-standalone"); const { Editor } = await import("ketcher-react"); setStructService(new StandaloneStructServiceProvider()); setEditor(Editor); }; initKetcher(); }, []); // 加载完成前显示占位内容 if (!Editor || !structService) { return <p>Loading editor...</p>; } return ( <Editor staticResourcesUrl="" structServiceProvider={structService} errorHandler={(err) => console.log(err)} /> ); }
Page.tsx保持原有动态导入逻辑即可:
import dynamic from "next/dynamic"; import "ketcher-react/dist/index.css"; const KetcherEditorReact = dynamic(() => import("./KetcherEditorReact"), { ssr: false, loading: () => <p>Loading editor...</p>, }); export default function Home() { return <KetcherEditorReact />; }
解决方案二:用环境判断包裹顶层初始化代码
如果你不想用useEffect,可以通过typeof window !== 'undefined'判断环境,仅在客户端初始化服务:
import { Editor } from "ketcher-react"; import "ketcher-react/dist/index.css"; let structServiceProvider: any = null; // 仅在浏览器环境初始化 if (typeof window !== 'undefined') { const { StandaloneStructServiceProvider } = require("ketcher-standalone"); structServiceProvider = new StandaloneStructServiceProvider(); } export default function KetcherEditorReact() { if (!structServiceProvider) { return <p>Loading editor...</p>; } return ( <Editor staticResourcesUrl="" structServiceProvider={structServiceProvider} errorHandler={(err) => console.log(err)} /> ); }
注意:此方案依赖
require而非ES模块导入,在TypeScript项目中可能需要调整tsconfig.json的moduleResolution配置。
关键说明
- 不要在模块顶层直接导入或初始化依赖
window的代码,因为Next.js在SSR阶段会解析所有模块的顶层代码。 dynamic({ ssr: false })仅能阻止组件的渲染逻辑在SSR执行,但无法阻止模块顶层代码的解析。
内容的提问来源于stack exchange,提问作者Forum
相关产品推荐
相关产品推荐

