Capítulo 110 de 456

Script Component

Core Idea

<Script> (next/script) otimiza o carregamento de scripts de terceiros via estratégias de timing (strategy), controlando quando cada script baixa/executa em relação à hidratação da página.

Key Concepts

  • src: obrigatório, a não ser que use script inline.
  • strategy="beforeInteractive": injetado no HTML inicial pelo servidor, baixado antes de qualquer módulo Next.js; deve ficar num root layout (app/layout.tsx); sempre acaba no <head> independente de onde é declarado; roda uma vez por document load (não repete em navegação client-side); use só para scripts críticos (bot detectors, cookie consent).
  • strategy="afterInteractive" (default): injetado client-side, carrega após parte/toda a hidratação; pode ficar em qualquer page/layout; bom para tag managers, analytics.
  • strategy="lazyOnload": injetado durante idle time do browser, após todos os recursos da página; bom para chat widgets, social widgets.
  • strategy="worker" (experimental, instável): offload para web worker; requer experimental.nextScriptWorkers: true; só funciona em pages/, não em App Router.
  • onLoad/onReady/onError: só funcionam em Client Components ('use client'); onLoad roda uma vez após carregar (não usável com beforeInteractive, use onReady); onReady roda no load inicial e a cada remount do componente (ex. após navegação); onError captura falha de carregamento (não usável com beforeInteractive).

Code Examples

import Script from 'next/script'

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        {children}
        <Script src="https://example.com/script.js" strategy="beforeInteractive" />
      </body>
    </html>
  )
}
  • O que demonstra: script crítico carregado antes da hidratação, colocado no root layout (sempre acaba no <head> independente da posição do JSX).
'use client'

import { useRef } from 'react'
import Script from 'next/script'

export default function Page() {
  const mapRef = useRef()

  return (
    <>
      <div ref={mapRef}></div>
      <Script
        id="google-maps"
        src="https://maps.googleapis.com/maps/api/js"
        onReady={() => {
          new google.maps.Map(mapRef.current, { center: { lat: -34.397, lng: 150.644 }, zoom: 8 })
        }}
      />
    </>
  )
}
  • O que demonstra: onReady reinstanciando um widget de terceiro (Google Maps) toda vez que o componente remonta.

Reference Tables

PropExampleTypeRequired
srcsrc="http://example.com/script"StringSim, exceto script inline
strategystrategy="lazyOnload"String-
onLoadonLoad={onLoadFunc}Function-
onReadyonReady={onReadyFunc}Function-
onErroronError={onErrorFunc}Function-

Anti-patterns

  • onLoad/onReady/onError em Server Component: não funcionam, exigem 'use client'.
  • onLoad/onError com strategy="beforeInteractive": incompatível; use onReady no lugar de onLoad.
  • strategy="worker" no App Router: ainda não funciona (só pages/), e é experimental/instável.
  • Colocar beforeInteractive fora do root layout: precisa estar no root layout para carregar em todas as páginas.
  • Esperar que beforeInteractive recarregue em navegação client-side que só troca root param: não recarrega, roda uma vez por document load.

Key Takeaways

  1. Escolha a strategy pelo grau de urgência: beforeInteractive (crítico) > afterInteractive (default, analytics/tags) > lazyOnload (baixa prioridade) > worker (experimental).
  2. beforeInteractive sempre migra para o <head> do HTML, não importa onde no JSX foi declarado.
  3. Use onReady em vez de onLoad quando o script precisa reinicializar a cada navegação/remount (widgets como mapas).

Connects To

  • Components (ch105): índice dos componentes built-in.
  • Image Component (ch108) e Font (ch106): outras otimizações de recurso externo no App Router.