본문으로 건너뛰기

문서 헤드 관리

문서 헤드 관리는 문서의 head, title, meta, link, script 태그를 관리하는 과정입니다. TanStack Router는 Start를 사용하는 풀스택 애플리케이션과 TanStack Router를 사용하는 단일 페이지 애플리케이션에서 문서 헤드를 관리하는 견고한 방법을 제공합니다. 다음 기능을 제공합니다.

  • titlemeta 태그의 자동 중복 제거
  • 라우트 표시 여부에 따른 태그 자동 로드/언로드
  • 중첩 라우트의 titlemeta 태그를 조합하는 방법

Start를 사용하는 풀스택 애플리케이션과 TanStack Router를 사용하는 단일 페이지 애플리케이션 모두에서 문서 헤드 관리는 다음과 같은 이유로 모든 애플리케이션의 중요한 부분입니다.

  • SEO
  • 소셜 미디어 공유
  • 분석
  • CSS 및 JS 로드/언로드

문서 헤드를 관리하려면 <HeadContent /><Scripts /> 컴포넌트를 모두 렌더링하고 routeOptions.head 속성을 사용해야 합니다. 이 속성은 title, meta, links, styles, scripts 속성이 있는 객체를 반환합니다.

문서 헤드 관리

export const Route = createRootRoute({
head: () => ({
meta: [
{
name: 'description',
content: 'My App is a web application',
},
{
title: 'My App',
},
],
links: [
{
rel: 'icon',
href: '/favicon.ico',
},
],
styles: [
{
media: 'all and (max-width: 500px)',
children: `p {
color: blue;
background-color: yellow;
}`,
},
],
scripts: [
{
src: 'https://www.google-analytics.com/analytics.js',
},
],
}),
})

중복 제거

기본적으로 TanStack Router는 titlemeta 태그를 중복 제거하며, 중첩 라우트에서 발견되는 각 태그의 마지막 항목을 우선합니다.

  • 중첩 라우트에 정의된 title 태그는 부모 라우트에 정의된 title 태그를 재정의합니다(함께 조합할 수도 있으며, 이 가이드의 뒤쪽에서 설명합니다).
  • meta 태그에서 동일한 name 또는 property를 가진 태그는 중첩 라우트에서 발견되는 해당 태그의 마지막 항목으로 재정의됩니다.

<HeadContent />

문서의 head, title, meta, link 및 헤드 관련 script 태그를 렌더링하려면 <HeadContent /> 컴포넌트가 필수입니다.

애플리케이션이 <head> 태그를 관리하지 않거나 관리할 수 없다면 루트 레이아웃의 <head> 태그 안 또는 가능한 한 컴포넌트 트리의 높은 위치에서 렌더링해야 합니다.

manifest로 관리되는 에셋의 경우 생성되는 script 프리로드 및 스타일시트 링크에 crossorigin 값도 설정할 수 있습니다.

<HeadContent assetCrossOrigin="anonymous" />

<HeadContent
assetCrossOrigin={{
script: 'anonymous',
stylesheet: 'use-credentials',
}}
/>

assetCrossOrigin은 Start가 생성하는 manifest 관리 에셋 링크에만 적용됩니다. assetCrossOrigincrossOrigintransformAssets를 통해 설정해도(객체 축약형 또는 콜백 반환값 중 하나로) 우선합니다.

Start/풀스택 애플리케이션

React

import { HeadContent } from '@tanstack/react-router'

export const Route = createRootRoute({
component: () => (
<html>
<head>
<HeadContent />
</head>
<body>
<Outlet />
</body>
</html>
),
})

Solid

import { HeadContent } from '@tanstack/solid-router'

export const Route = createRootRoute({
component: () => (
<html>
<head>
<HeadContent />
</head>
<body>
<Outlet />
</body>
</html>
),
})

단일 페이지 애플리케이션

먼저 index.html에 <title> 태그를 설정했다면 제거합니다.

React

import { HeadContent } from '@tanstack/react-router'

const rootRoute = createRootRoute({
component: () => (
<>
<HeadContent />
<Outlet />
</>
),
})

Solid

import { HeadContent } from '@tanstack/solid-router'

const rootRoute = createRootRoute({
component: () => (
<>
<HeadContent />
<Outlet />
</>
),
})

본문 스크립트 관리

<head> 태그에 렌더링할 수 있는 스크립트 외에도 routeOptions.scripts 속성을 사용해 <body> 태그에 스크립트를 렌더링할 수 있습니다. DOM이 로드된 후 애플리케이션의 메인 진입점보다 먼저 실행해야 하는 스크립트(인라인 스크립트 포함)를 로드할 때 유용합니다. 메인 진입점에는 Start 또는 TanStack Router의 풀스택 구현을 사용하는 경우 하이드레이션도 포함됩니다.

이를 위해 다음을 수행해야 합니다.

export const Route = createRootRoute({
scripts: () => [
{
children: 'console.log("Hello, world!")',
},
],
})

<Scripts />

문서의 본문 스크립트를 렌더링하려면 <Scripts /> 컴포넌트가 필수입니다. 애플리케이션이 <body> 태그를 관리하지 않거나 관리할 수 없다면 루트 레이아웃의 <body> 태그 안 또는 가능한 한 컴포넌트 트리의 높은 위치에서 렌더링해야 합니다.

예시

React

import { createRootRoute, Scripts } from '@tanstack/react-router'
export const Route = createFileRoute('/')({
component: () => (
<html>
<head />
<body>
<Outlet />
<Scripts />
</body>
</html>
),
})

Solid

import { createFileRoute, Scripts } from '@tanstack/solid-router'
export const Route = createRootRoute('/')({
component: () => (
<html>
<head />
<body>
<Outlet />
<Scripts />
</body>
</html>
),
})

ScriptOnce를 사용한 인라인 스크립트

React가 하이드레이션되기 전에 실행해야 하는 스크립트(테마 감지 등)에는 ScriptOnce를 사용합니다. 스타일이 적용되지 않은 콘텐츠가 잠시 표시되는 현상(FOUC)이나 테마 깜빡임을 방지할 때 특히 유용합니다.

React

import { ScriptOnce } from '@tanstack/react-router'

const themeScript = `(function() {
try {
const theme = localStorage.getItem('theme') || 'auto';
const resolved = theme === 'auto'
? (matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')
: theme;
document.documentElement.classList.add(resolved);
} catch (e) {}
})();`

function ThemeProvider({ children }) {
return (
<>
<ScriptOnce children={themeScript} />
{children}
</>
)
}

Solid

import { ScriptOnce } from '@tanstack/solid-router'

const themeScript = `(function() {
try {
const theme = localStorage.getItem('theme') || 'auto';
const resolved = theme === 'auto'
? (matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')
: theme;
document.documentElement.classList.add(resolved);
} catch (e) {}
})();`

function ThemeProvider({ children }) {
return (
<>
<ScriptOnce children={themeScript} />
{children}
</>
)
}

ScriptOnce 작동 방식

  1. SSR 중에 제공된 코드가 포함된 <script> 태그를 렌더링합니다.
  2. 브라우저가 HTML을 파싱할 때(React가 하이드레이션되기 전에) 스크립트가 즉시 실행됩니다.
  3. 실행이 끝나면 스크립트가 DOM에서 자신을 제거합니다.
  4. 클라이언트 측 탐색에서는 아무것도 렌더링하지 않습니다(중복 실행을 방지합니다).

React

하이드레이션 경고 방지

스크립트가 하이드레이션 전에 DOM을 수정하는 경우(예: <html>에 클래스 추가) suppressHydrationWarning을 사용해 React 경고를 방지합니다.

export const Route = createRootRoute({
component: () => (
<html lang="en" suppressHydrationWarning>
<head>
<HeadContent />
</head>
<body>
<ThemeProvider>
<Outlet />
</ThemeProvider>
<Scripts />
</body>
</html>
),
})

일반적인 사용 사례

  • 테마/다크 모드 감지 - 깜빡임을 방지하도록 하이드레이션 전에 테마 클래스를 적용합니다.
  • 기능 감지 - 렌더링 전에 브라우저 기능을 확인합니다.
  • 분석 초기화 - 사용자 상호작용 전에 추적을 초기화합니다.
  • 핵심 경로 설정 - 하이드레이션 전에 실행해야 하는 모든 JavaScript입니다.