Next的Script和原生 <script>`标签区别

6 分钟
55 阅读

在 Next.js 中,next/script 是框架封装的优化版脚本加载组件,相比原生 <script> 标签,核心优势是 支持高级加载策略、自动优化性能、适配 Next.js 渲染逻辑,尤其适合生产环境和复杂脚本场景。下面从「核心区别、用法对比、适用场景」三方面详细拆解:

一、核心区别(表格总结)

对比维度 原生 <script> 标签 Next.js next/script 组件
加载策略 仅支持 async/defer 基础属性,无细粒度控制 支持 strategy 配置(beforeInteractive/afterInteractive/lazyOnload/worker),精准控制加载时机
渲染适配 客户端渲染(CSR)中正常工作,但 SSR/SSG 时可能导致 hydration 不匹配 自动适配 SSR/SSG/ISR 渲染模式,避免 hydration 错误,脚本执行时机与渲染流程对齐
性能优化 无内置优化,需手动处理脚本加载阻塞、重复加载问题 自动去重(同一脚本不重复加载)、支持预加载、部分策略下脚本加载不阻塞页面渲染
脚本位置 需手动指定 head/body 位置(如 next/head 中) 无需手动指定位置,框架根据 strategy 自动插入最优位置(如 beforeInteractive 插入 <head>
动态脚本(如 CDN 链接) 直接写链接,但 SSR 时可能因跨域/时机问题失效 支持动态链接(如环境变量拼接),且框架会处理跨域脚本的加载兼容性
事件监听 需手动绑定 onload/onerror 事件 内置 onLoad/onError 回调 props,使用更便捷
Worker 脚本支持 需手动创建 Worker 实例,配置复杂 支持 strategy="worker",一键将脚本放入 Web Worker 执行,避免阻塞主线程

二、用法对比(代码示例)

1. 加载第三方 CDN 脚本(如 jQuery、PayPal SDK)

原生 <script> 标签(Next.js 中使用)
jsx 复制代码
// 需手动导入 next/head,且只能用 async/defer 控制加载
import Head from 'next/head';

export default function Page() {
  return (
    <>
      <Head>
        {/* 只能选择 async 或 defer,无法控制脚本在页面交互前/后执行 */}
        <script
          src="https://cdn.jsdelivr.net/npm/jquery@3.6.4/dist/jquery.min.js"
          async
          onLoad={() => console.log('jQuery 加载完成')}
        />
      </Head>
    </>
  );
}
Next.js next/script 组件
jsx 复制代码
// 导入组件即可,无需手动指定 head/body 位置
import Script from 'next/script';

export default function Page() {
  return (
    <>
      <Script
        src="https://cdn.jsdelivr.net/npm/jquery@3.6.4/dist/jquery.min.js"
        // 配置加载策略:页面交互后加载(不阻塞首屏)
        strategy="afterInteractive"
        // 内置回调,无需手动绑定
        onLoad={() => console.log('jQuery 加载完成')}
        onError={(err) => console.log('加载失败', err)}
      />
    </>
  );
}

2. 加载本地脚本(如 public/js/custom.js

原生 <script> 标签
jsx 复制代码
// 需拼接 public 路径,且 SSR 时可能执行时机错乱
import Head from 'next/head';

export default function Page() {
  return (
    <>
      <Head>
        <script src="/js/custom.js" defer />
      </Head>
    </>
  );
}
Next.js next/script 组件(支持策略+自动路径处理)
jsx 复制代码
import Script from 'next/script';

export default function Page() {
  return (
    <>
      {/* 无需拼接 public 路径,直接写相对路径 */}
      <Script
        src="/js/custom.js"
        // 关键脚本:页面交互前加载(如初始化全局状态的脚本)
        strategy="beforeInteractive"
      />
    </>
  );
}

3. 特殊场景:Web Worker 脚本(避免阻塞主线程)

原生 <script> 标签(复杂)
jsx 复制代码
export default function Page() {
  useEffect(() => {
    // 手动创建 Worker,需处理路径、兼容性、销毁等问题
    const worker = new Worker('/js/heavy-task.js');
    worker.postMessage({ data: '任务数据' });
    worker.onmessage = (e) => console.log('Worker 结果', e.data);
    return () => worker.terminate(); // 手动销毁
  }, []);

  return <div>原生 Worker 示例</div>;
}
Next.js next/script 组件(一键实现)
jsx 复制代码
import Script from 'next/script';

export default function Page() {
  return (
    <>
      {/* strategy="worker" 自动将脚本放入 Worker 执行,无需手动处理 */}
      <Script
        src="/js/heavy-task.js"
        strategy="worker"
        onLoad={() => console.log('Worker 脚本加载完成')}
      />
    </>
  );
}

三、next/script 核心优势详解

1. 四大加载策略,精准控制执行时机(最核心优势)

strategy 属性是 next/script 的灵魂,解决了原生脚本加载时机难以控制的问题:

  • beforeInteractive:仅支持 SSR/SSG,脚本在页面「可交互前」加载(如 next/head 中),适合关键脚本(如初始化全局配置、监控脚本);
  • afterInteractive:默认值,脚本在页面「可交互后」加载(类似 defer 但优化更好),不阻塞首屏渲染,适合非关键第三方脚本(如统计、广告);
  • lazyOnload:脚本在页面「完全加载+空闲时」加载(类似 requestIdleCallback),适合非紧急脚本(如隐藏组件的脚本、辅助功能);
  • worker:脚本在 Web Worker 中执行,不占用主线程,适合耗时操作(如数据处理、复杂计算)。

2. 自动适配 Next.js 渲染模式,避免 hydration 错误

Next.js 是 SSR/SSG 框架,原生 <script> 可能在服务端渲染时被插入,但客户端 hydration 时重复执行,导致状态错乱。next/script 会自动处理:

  • SSR 时:脚本仅在客户端执行,避免服务端渲染时的跨域/环境问题;
  • Hydration 时:确保脚本执行时机与客户端渲染对齐,不会出现「脚本已执行但 DOM 未挂载」的错误。

3. 性能优化:去重+预加载

  • 自动去重:同一 srcid 的脚本不会重复加载,避免原生脚本因组件复用导致的重复执行问题;
  • 预加载优化:框架会根据加载策略自动预加载脚本(如 beforeInteractive 脚本会被优先预加载),提升加载速度;
  • 无阻塞渲染:除 beforeInteractive 外,其他策略的脚本加载均不阻塞页面渲染,优化首屏加载时间(LCP)。

4. 更便捷的事件处理与配置

  • 内置 onLoad/onError 回调,无需手动绑定 addEventListener
  • 支持 id/nonce/integrity 等安全属性,满足生产环境安全要求;
  • 支持动态 src(如通过环境变量拼接 CDN 链接),适配多环境部署:
    jsx 复制代码
    <Script src={`${process.env.NEXT_PUBLIC_CDN_URL}/js/custom.js`} />

四、适用场景与注意事项

什么时候用 next/script

  • 生产环境项目(需要性能优化、渲染适配);
  • 加载第三方脚本(如统计、支付、广告 SDK);
  • 需要控制加载时机的脚本(如关键脚本、非紧急脚本);
  • 需使用 Web Worker 的耗时脚本;
  • SSR/SSG/ISR 渲染模式的页面(避免 hydration 错误)。

什么时候用原生 <script>

  • 简单静态页面(无需优化,快速开发);
  • 客户端渲染(CSR)的简单组件(无 SSR 需求);
  • 需自定义复杂加载逻辑(如动态插入脚本且无需 Next.js 优化)。

注意事项

  • strategy="beforeInteractive" 仅支持放在 pages/_document.js 或根布局(App Router)中,不能放在普通页面/组件;
  • 本地脚本需放在 public 文件夹下,src 路径直接写 /文件名(无需 public/ 前缀);
  • 第三方脚本需确保支持跨域(大部分 CDN 脚本都支持),否则可能加载失败;
  • 生产环境建议给脚本添加 integrity 属性(校验脚本完整性,防止篡改):
    jsx 复制代码
    <Script
      src="https://cdn.jsdelivr.net/npm/jquery@3.6.4/dist/jquery.min.js"
      integrity="sha256-oP6HI9z1XaZNBrJURtCoUT5SUnxFr8s3BzRl+cbzUq8="
      crossOrigin="anonymous"
    />

总结

next/script 是 Next.js 为脚本加载量身打造的优化方案,核心优势是「加载策略可控、渲染适配、性能优化」,完全覆盖原生 <script> 的功能且解决了其在 Next.js 中的痛点。生产环境优先使用 next/script,尤其对于 SSR/SSG 项目和需要优化性能的场景;简单场景或临时调试时,原生 <script> 也可满足需求。

评论

评论

发表评论