Script 脚本
2026年9月6日
第三方统计、地图、偶尔要嵌的旧库,用 next/script 比手写 <script> 好管:去重、按策略插入、跟路由生命周期对齐。
局部引入
只在某条路由需要时,写在该 page.tsx:
import Script from "next/script";
export default function Page() {
return (
<div>
<Script src="https://example.com/sdk.js" />
</div>
);
}
tsx
切到这条路由才加载,之后走缓存。底层仍是往文档里插 <script>。
全局引入
放进根 layout.tsx,全站一份:
import Script from "next/script";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="zh-CN">
<body>
{children}
<Script src="https://example.com/sdk.js" strategy="afterInteractive" />
</body>
</html>
);
}
tsx
不必塞进 <head>,组件自己会找合适位置。
strategy
| 值 | 时机 | 备注 |
|---|---|---|
beforeInteractive | 页面可交互之前 | 会挡住渲染,只给真正关键的脚本 |
afterInteractive | 水合之后(默认) | 统计、一般 SDK |
lazyOnload | 浏览器空闲 | 聊天挂件、非关键 |
worker | 实验性 | 不稳定,先别用 |
给脚本一个稳定 id,方便框架去重和排错:
<Script id="analytics" strategy="afterInteractive" src="https://example.com/a.js" />
tsx
内联
没有外链时,用子节点或 dangerouslySetInnerHTML。必须带 id。
<Script id="boot" strategy="afterInteractive">
{`window.__boot = true`}
</Script>
tsx
<Script
id="boot-2"
strategy="afterInteractive"
dangerouslySetInnerHTML={{
__html: `window.__boot = true`,
}}
/>
tsx
能外链就外链,内联不好缓存,也更容易和 CSP 打架。
事件
onLoad、onReady、onError 要在客户端组件里才靠谱:
"use client";
import Script from "next/script";
export default function Map() {
return (
<Script
src="https://example.com/map.js"
onLoad={() => console.log("loaded")}
onReady={() => console.log("ready or remounted")}
onError={() => console.error("failed")}
/>
);
}
tsx
onLoad:脚本第一次加载成功onReady:加载完成,以及组件以后每次挂载onError:失败
能 npm 装进仓库的库,优先 import,不要用 Script 从 CDN 拉 React 生态包。Script 留给「只能给一段外链」的第三方。
下一篇开始静态导出:纯 HTML 怎么打出来,以及哪些能力会丢掉。