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>

👉点击进入 我的网站

相关推荐
匠心网络科技2 小时前
前端框架-Vue双向绑定核心机制全解析
前端·javascript·vue.js·前端框架
爱编码的傅同学2 小时前
【线程的同步与互斥】初识互斥量与锁
android·java·开发语言
Jinuss2 小时前
源码分析之React中的FiberRoot节点属性介绍
前端·javascript·react.js
wjs20242 小时前
PHP $_GET 变量详解
开发语言
Zxxxxxy_2 小时前
Spring MVC
开发语言·spring·maven
思茂信息2 小时前
CST仿真实例:手机Type-C接口ESD仿真
c语言·开发语言·单片机·嵌入式硬件·智能手机·cst·电磁仿真
2501_944526422 小时前
Flutter for OpenHarmony 万能游戏库App实战 - 收藏功能实现
android·java·开发语言·javascript·python·flutter·游戏
2501_944526422 小时前
Flutter for OpenHarmony 万能游戏库App实战 - 个人中心实现
android·java·javascript·python·flutter·游戏
自回归向前看2 小时前
2020-25 Js ES新增加特性
前端·javascript