Next.js Script 组件详解

文章目录

    • [一、为什么不能直接用 `<script>`?](#一、为什么不能直接用 <script>?)
      • [1️⃣ 阻塞页面渲染](#1️⃣ 阻塞页面渲染)
      • [2️⃣ 执行时机不可控](#2️⃣ 执行时机不可控)
      • [3️⃣ 无法被 Next.js 优化](#3️⃣ 无法被 Next.js 优化)
    • [二、什么是 `next/script`?](#二、什么是 next/script?)
    • [三、基本引入 vs 全局引入(非常容易混淆)](#三、基本引入 vs 全局引入(非常容易混淆))
      • [3.1 什么是「基本引入」(页面级 / 组件级)?](#3.1 什么是「基本引入」(页面级 / 组件级)?)
      • [3.2 什么是「全局引入」(应用级)?](#3.2 什么是「全局引入」(应用级)?)
    • [四、Script 的加载策略](#四、Script 的加载策略)
      • [4.1 `afterInteractive`(默认 & 首选)](#4.1 afterInteractive(默认 & 首选))
      • [4.2 `lazyOnload`(性能最优)](#4.2 lazyOnload(性能最优))
      • [4.3 `beforeInteractive`(慎用)](#4.3 beforeInteractive(慎用))
      • [4.4 `worker`(实验特性)](#4.4 worker(实验特性))
    • [四、内联 Script 的写法](#四、内联 Script 的写法)

在 Next.js 中,next/script 是一个经常被忽略、但在性能和工程质量上非常关键的组件。它专门用于安全、可控、性能友好地加载第三方脚本(如统计、监控、广告、SDK 等)。

一、为什么不能直接用 <script>

在传统 HTML 中,我们习惯这样写:

html 复制代码
<script src="https://example.com/sdk.js"></script>

但在 Next.js(尤其是 App Router / SSR 场景) 中,这种写法存在明显问题:

1️⃣ 阻塞页面渲染

  • 默认 script 会阻塞 HTML 解析
  • 影响 首屏性能(FCP / LCP)

2️⃣ 执行时机不可控

  • SSR / Hydration 阶段容易出现

    • window is not defined
    • 客户端、服务端不一致

3️⃣ 无法被 Next.js 优化

  • 无法参与 Script 调度
  • 无法延迟 / 优先级控制

👉 Next.js Script 的存在,本质就是为了解决这些问题。

二、什么是 next/script

ts 复制代码
import Script from "next/script";

Script 是 Next.js 提供的一个高级 Script 管理组件,具备:

  • ✅ 不阻塞渲染
  • ✅ 精准控制加载与执行时机
  • ✅ SSR / CSR 安全
  • ✅ 自动去重
  • ✅ 性能优化(preload / defer)

三、基本引入 vs 全局引入(非常容易混淆)

在使用 next/script 时,很多人其实不是不会用 strategy,而是没想清楚:脚本应该"在哪引入"

我们先把这个问题讲清楚,再进入 strategy。

3.1 什么是「基本引入」(页面级 / 组件级)?

👉 只在某一个页面或组件中使用 Script

示例:仅在详情页引入

ts 复制代码
// app/detail/page.tsx
import Script from "next/script";

export default function DetailPage() {
  return (
    <>
      <Script src="https://example.com/detail-sdk.js" strategy="afterInteractive" />
      <div>Detail Page</div>
    </>
  );
}

特点

  • 只在该页面加载
  • ✅ 页面卸载后不再使用(逻辑上)
  • ❌ 切换页面可能重新执行

适合场景

  • 只在某个页面用到的 SDK
  • 页面级功能(编辑器、地图、播放器)
  • 不希望污染全局的脚本

3.2 什么是「全局引入」(应用级)?

👉 在应用根节点引入,一次加载,全站可用

App Router(推荐方式)

ts 复制代码
// app/layout.tsx
import Script from "next/script";

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        <Script src="https://example.com/global-sdk.js" strategy="afterInteractive" />
      </body>
    </html>
  );
}

特点

  • 全站只加载一次(自动去重)
  • ✅ 所有页面都能使用 window.xxx
  • ❌ 会增加全站的 JS 成本

适合场景

  • 埋点 / 监控(GA、神策、Sentry)
  • 登录态相关 SDK
  • 全局基础能力

四、Script 的加载策略

90% 的脚本:用 afterInteractive > 不影响首屏的:用 lazyOnload > 极少数基础脚本:才用 beforeInteractive

4.1 afterInteractive(默认 & 首选)

tsx 复制代码
<Script src="https://example.com/sdk.js" />
  • 页面可交互后加载
  • 不阻塞渲染
  • 行为最可控

埋点 / 监控 / 业务 SDK 首选

4.2 lazyOnload(性能最优)

tsx 复制代码
<Script src="https://example.com/chat.js" strategy="lazyOnload" />
  • 页面完全加载后再执行
  • 对首屏几乎 0 影响

广告 / 客服 / 非关键功能

4.3 beforeInteractive(慎用)

tsx 复制代码
<Script src="https://example.com/polyfill.js" strategy="beforeInteractive" />
  • React 执行前加载
  • 可能影响首屏性能

⚠️ 只有当脚本"必须最早存在"时才用

4.4 worker(实验特性)

tsx 复制代码
<Script src="https://example.com/heavy.js" strategy="worker" />

暂时不建议使用。

四、内联 Script 的写法

方式一:dangerouslySetInnerHTML

ts 复制代码
<Script
  id="ga-init"
  strategy="afterInteractive"
  dangerouslySetInnerHTML={{
    __html: `
      window.dataLayer = window.dataLayer || [];
      function gtag(){dataLayer.push(arguments);}
      gtag('js', new Date());
    `
  }}
/>

⚠️ 必须提供 唯一 id ,否则 Next.js 会报错

方式二:children(推荐)

tsx 复制代码
<Script id="init" strategy="afterInteractive">
  {`console.log('script loaded')`}
</Script>

👉点击进入 我的网站

相关推荐
新缸中之脑3 小时前
开发AI代理必备的8个Python 库
开发语言·人工智能·python
暴走十八步3 小时前
PHP+vscode开启调试debug
开发语言·vscode·php
郝学胜-神的一滴3 小时前
Python 列表 vs 数组:深入解析与最佳选择指南
开发语言·python·程序人生
杜子不疼.3 小时前
基于ATVC模板库的Ascend C Vector算子快速开发指南
c语言·开发语言·mfc
MSTcheng.3 小时前
【C++】C++11新特性(三)
开发语言·c++·c++11
learning-striving3 小时前
kali连不上网解决方法
linux·开发语言·网络·php·kali
田野追逐星光3 小时前
STL容器list的模拟实现
开发语言·c++·list
NCDS程序员3 小时前
v-model: /v-model/ :(v-bind)三者核心区别
前端·javascript·vue.js
摇滚侠3 小时前
macbook shell 客户端推荐 Electerm macbook 版本下载链接
java·开发语言
程序员布吉岛3 小时前
Java 后端定时任务怎么选:@Scheduled、Quartz 还是 XXL-Job?(对比 + 避坑 + 选型)
java·开发语言