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>

👉点击进入 我的网站

相关推荐
我命由我123454 小时前
CesiumJS 笔记 - 获取容器中心点、Cartesian3 clone 方法、修改 Cartesian3 对象的高度
前端·javascript·css·前端框架·html·html5·js
抱抱宝5 小时前
Agent-study项目教程(03):手写 Mini-ReAct Agent(不依赖框架)
javascript·人工智能·gpt·react.js·prompt·agent
用户938515635076 小时前
Next.js 笔记系统(二):Redis 数据服务与侧边栏组件拆分实战
javascript·全栈
WWJA王文举6 小时前
I²C通信完整流程详解:START、地址、ACK、数据、Repeated START和STOP一次讲透
c语言·开发语言
zhanghaha13146 小时前
Python进阶教程:6_JSON 数据解析 —— 新手完全指南
开发语言·python·json
qq_448011168 小时前
C语言中的动态内存分配
c语言·开发语言·php
汉字萌萌哒8 小时前
2024CSP-J入门级C++真题详解
开发语言·c++
arbboter9 小时前
【网络工具】NetProxy网络代理用户手册
开发语言·网络·c#·网络代理·网络异常·代理工具
Heo10 小时前
大厂前端调试不能只会debugger
前端·javascript·面试
汉字萌萌哒10 小时前
2019CCF-CSP入门级C++试题解析
java·开发语言·c++