在NextJS中无需props或context向React组件添加script标签的方案
可行解决方案
针对你在SSR模式NextJS(Pages Router)中注入script且避免相关内容进入NEXT_DATA的需求,可按实际场景选择以下方案:
方案1:直接在_document.tsx服务端获取并注入script(推荐需要首屏存在script的场景)
_document.tsx的逻辑仅在服务端运行,其中返回的属性仅用于服务端渲染HTML模板,不会被序列化到客户端的NEXT_DATA中,完全符合你的需求。
示例代码:
// pages/_document.tsx import { Html, Head, Main, NextScript, DocumentContext } from 'next/document' type DocumentProps = { externalScriptUrl: string } export default function Document({ externalScriptUrl }: DocumentProps) { return ( <Html lang="zh-CN"> <Head> {/* 直接注入script,可按需添加async/defer属性 */} <script src={externalScriptUrl} async /> </Head> <body> <Main /> <NextScript /> </body> </Html> ) } Document.getInitialProps = async (ctx: DocumentContext) => { const initialProps = await Document.defaultGetInitialProps(ctx) // 服务端直接调用API获取script相关配置,该逻辑完全不会暴露到客户端 const apiRes = await fetch('你的业务API地址,用于获取script地址/内容') const { scriptUrl } = await apiRes.json() return { ...initialProps, externalScriptUrl: scriptUrl } }
方案2:客户端动态加载script(适合不需要首屏就加载的script)
所有逻辑在客户端侧执行,服务端完全不处理相关数据,自然不会有内容进入NEXT_DATA。你之前使用window失败大概率是因为在SSR阶段直接调用了客户端API,将逻辑放入useEffect即可规避这个问题。
示例代码:
// 任意需要引入script的组件内 import { useEffect } from 'react' const YourComponent = () => { useEffect(() => { const loadThirdScript = async () => { // 客户端侧请求获取script配置,或直接硬编码地址 const res = await fetch('你的业务API地址') const { scriptUrl } = await res.json() // 动态创建script标签 const script = document.createElement('script') script.src = scriptUrl script.async = true // 可按需添加加载成功/失败回调 script.onload = () => console.log('第三方库加载完成') script.onerror = () => console.error('第三方库加载失败') document.head.appendChild(script) } loadThirdScript() }, []) return <div>你的组件内容</div> } export default YourComponent
也可以直接用NextJS官方提供的next/script组件,比手动创建性能更优:
import Script from 'next/script' import { useState, useEffect } from 'react' const YourComponent = () => { const [scriptUrl, setScriptUrl] = useState('') useEffect(() => { const getScriptUrl = async () => { const res = await fetch('你的业务API地址') const { scriptUrl } = await res.json() setScriptUrl(scriptUrl) } getScriptUrl() }, []) return ( <> {scriptUrl && <Script src={scriptUrl} strategy="afterInteractive" />} <div>你的组件内容</div> </> ) }
注意事项
- 如果使用
_document.tsx方案,不要在getInitialProps中返回不必要的敏感数据,所有返回值仅会用于渲染静态HTML,不会进入客户端上下文。 - 如果你的项目已经升级到NextJS 13+ App Router,直接在根服务端布局组件中请求script配置并渲染script标签即可,服务端组件的所有数据处理逻辑都不会暴露到客户端,也不会生成
NEXT_DATA相关内容。
内容的提问来源于stack exchange,提问作者WhyyyHalp
相关产品推荐
相关产品推荐

