NextJS深度链接/页面刷新时全局变量丢失问题咨询
问题描述
在Next.js的Pages/_document.tsx中引入了全局配置脚本,脚本会在window对象上设置全局变量。首页加载正常,但嵌套路由页面刷新或通过深度链接访问时,抛出ReferenceError: window is not defined错误。需求为仅在客户端使用该配置,且不想在构建阶段打包配置变量,希望发布时直接更新变量,询问当前方案是否可行及解决办法。
对应的代码实现:
import Script from 'next/script' ... ... render() { return ( <Html lang='en'> <Head> <meta charSet='UTF-8' /> <meta httpEquiv='X-UA-Compatible' content='IE=edge' /> </Head> <body> <Main /> <NextScript /> <Script src='/scripts/public-config.js' strategy='beforeInteractive' /> </body> </Html> ) }
解决方案
你的核心方案思路是可行的,问题出在脚本加载策略和window访问时机上,调整后就能满足需求:
更换脚本加载策略:将
strategy='beforeInteractive'改为strategy='afterInteractive'或strategy='lazyOnload'。beforeInteractive会在服务端渲染阶段尝试加载脚本,此时不存在window对象才导致报错;后两种策略仅在客户端环境执行,能彻底避免服务端层面的报错。确保客户端才访问全局变量:业务代码中使用
window上的配置时,先做客户端环境判断:// 组件内使用示例 if (typeof window !== 'undefined') { const appConfig = window.publicConfig; // 后续业务逻辑 }或者利用Next.js的
useEffect钩子(该钩子仅在客户端执行):import { useEffect } from 'react'; function TargetComponent() { useEffect(() => { const appConfig = window.publicConfig; // 在这里处理配置相关逻辑 }, []); // 组件其他内容 }脚本放置位置优化:可以把
<Script>标签移到_app.tsx中而非_document.tsx。_app.tsx的逻辑更偏向客户端,能更合理地控制脚本加载时机,同时完全不影响你在发布阶段替换public-config.js文件的需求——只要构建产物中该脚本是独立文件,发布时直接替换即可,无需重新构建整个应用。
调整后既能满足客户端加载配置、发布时动态更新变量的需求,又能彻底解决服务端渲染的window未定义错误。
内容的提问来源于stack exchange,提问作者conor909

