본문 바로가기

Next.js

Next.js 9-5 Metadata

  Next.js에는 향상된 SEO 및 웹 공유 가능성을 위해 애플리케이션 메타데이터(예: HTML 헤드 요소 내의 메타 및 링크 태그)를 정의하는 데 사용할 수 있는 메타데이터 API가 있다. 애플리케이션에 메타데이터를 추가할 수 있는 두 가지 방법이 있다.

Config-based Metadata layout.js 또는 pages.js 파일에서 정적 메타데이터 개체 또는 동적 generateMetadata 함수를 내보낸다.
File-based Metadata 경로 세그먼트에 정적 또는 동적으로 생성된 특수 파일을 추가한다.

  이 두 가지 옵션을 모두 사용하면 Next.js가 페이지에 대한 관련 <head> 요소를 자동으로 생성한다. ImageResponse 생성자를 사용하여 동적 OG 이미지를 생성할 수도 있다.

 

  • Static Metadata

  정적 메타데이터를 정의하려면 layout.js 또는 정적 page.js 파일에서 Metadata 개체를 내보낸다.

// layout.tsx / page.tsx

import { Metadata } from 'next';

export const metadata: Metadata = {
  title: '...',
  description: '...',
}

export default function Page() {}

 

  • Dynamic Metadata

  generateMetadata 함수를 사용하여 동적 값이 필요한 메타데이터를 가져올 수 있다.

// app/products/[id]/page.tsx

import { Metadata, ResolvingMetadata } from 'next'

type Props = {
  params: { id: string }
  searchParams: { [key: string]: string | string[] | undefined }
}

export async function generateMetadata(
  { params, searchParams }: Props,
  parent?: ResolvingMetadata
): Promise<Metadata> {
  // read route params
  const id = params.id
  
  // fetch data
  const product = await fetch(`htttps://.../${id}`).then((res) => res.json())
  
  // optionally access and extend (rather than replace) parent metadata
  const previousImages = (await parent).openGraph?.images || []
  
  return {
    title: product.title,
    openGraph: {
      images: ['/some-specific-page-image.jpg', ...previousImages],
    },
  }
}

export default function Page({ params, searchParams }: Props) {}

  generateMetadata를 통한 정적 및 동적 메타데이터는 모두 서버 컴포넌트에서만 지원된다. 그리고 경로를 렌더링 할 때 Next.js generateMetadata, generateStaticParams, Layouts, Pages 및 서버 컴포넌트에서 동일한 데이터에 대한 가져오기 요청을 자동으로 중복 제거한다. 가져오기를 사용할 수 없는 경우 React 캐시를 사용할 수 있다.

  Next.js는 UI를 클라이언트로 스트리밍 하기 전에 generateMetadata 내에서 데디터 가져오기가 완료될 때까지 기다린다. 이렇게 하면 스트리밍 응답의 첫 번째 부분에 <head> 태그가 포함된다.

 

  • File-based metadata

  다음 특수 파일은 메타데이터에 사용할 수 있다.

favicon.ico. apple-icon.jpg, and icon.jpg
opengraph-image.jpg and twiiter-image.jpg
robots.txt
sitemap.xml

  정적 메타데이터에 대해 이를 사용하거나 코드를 사용하여 프로그래밍 방식으로 이러한 파일을 생성할 수 있다.

 

  • Behavior

  파일 기반 메타데이터는 우선순위가 더 높으며 모든 구성 기반 메타데이터를 재정의한다.

 

  • Default Fields

  경로가 메타데이터를 정의하지 않는 경우에도 항상 추가되는 두 가지 기본 메타 태그가 있다. 첫째로 메타 문자셋 태그는 웹사이트의 문자 인코딩을 설정한다. 둘째로 메타 뷰포트 태그는 웹사이트의 뷰포트 너비와 배율을 설정하여 다양한 장치에 맞게 조정한다.

<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />

 

  • Ordering

  메타데이터는 루트 세그먼트에서 시작하여 마지막 page.js 세그먼트에 가장 가까운 세그먼트까지 순서대로 평가된다. 예를 들면,

  1. app/layout.tsx (Root Layout)
  2. app/blog/layout.tsx (Nested Blog Layout)
  3. app/blog/[slug]/page.tsx (Blog Page)

 

  • Merging

  평가 순서에 따라 동일한 경로의 여러 세그먼트에서 내보낸 메타데이터 개체는 얕게 병합되어 경로의 최종 메타데이터 출력을 형성한다. 중복 키는 순서에 따라 대체된다.

  즉, 이전 세그먼트에서 정의된 openGraph 및 로봇과 같은 중첩 필드가 있는 메타데이터는 이를 정의하기 위해 마지막 세그먼트로 덮어쓴다.

 

  • Overwriting fields
// app/layout.js

export const metadata = {
  title: 'Acme',
  openGraph: {
    title: 'Acme',
    description: 'Acme if a...',
  },
}
// app/blog/page.js

export const metadata = {
  title: 'Blog',
  openGraph: {
    title: 'Blog',
  },
}

// Output:
// <title>Blog</title>
// <meta property="og:title" content="Blog" />

  위의 예에서 app/layout.js의 제목은 app/blog/page.js의 제목으로 대체된다. app/blog/page.js가 openGraph 메타데이터를 설정하기 때문에 app/layout.js의 모든 openGraph 필드는 app/blog/page.js로 대체된다. openGraph.description이 없다는 점에 유의하면 된다.

  세그먼트 간에 일부 중첩된 필드를 공유하면서 다른 필드를 덮어쓰려는 경우 별도의 변수로 가져올 수 있다.

// app/shared-metadata.js

export const openGraphImage = { images: ['https://...'] }
// app/page.js

import { openGraphImage } from './shared-metadata'

export const metadata = {
  openGraph: {
    ...openGraphImage,
    title: 'Home',
  },
}

 

  • Inheriting fields
// app/layout.js

export const metadata = {
  title: 'Acme',
  openGraph: {
    title: 'Acme',
    dscription: 'Acme is a...',
  },
}
// app/about.page.js

export const metadata = {
  title: 'About',
}

// Output:
// <title>About</title>
// <meta property="og:title" content="Acme" />
// <meta property="og:description" content="Acme is a..." />

  app/layout.js의 제목은 app/about/page.js의 제목으로 대체된다. app/layout.js의 모든 openGraph 필드는 app/about/page.js가 openGraph 메타데이터를 설정하지 않기 때문에 app/about/page.js에서 상속된다.

 

  • Dynamic Image Generation

  ImageResponse 생성자를 사용하면 JSX 및 CSS를 사용하여 동적 이미지를 생성할 수 있다. Open Graph 이미지, Twitter 카드 등과 같은 소셜 미디어 이미지를 만드는 데 유용하다.

  ImageResponse는 Edge Runtime을 사용하고 Next.js는 Edge에서 캐시 된 이미지에 올바른 헤더를 자동으로 추가하여 성능을 개선하고 재계산을 줄이는 데 도움을 준다.

  이를 사용하려면 next/server에서 ImageResponse를 가져오면 된다.

// app/about/route.jsx

import { ImageResponse } from 'next/server'

export const runtime = 'edge'

export async function GET() {
  return new ImageResponse(
    (
      <div
        style={{
          fontSize: 128,
          bacground: 'white',
          width: '100%',
          height: '100%',
          display: 'flex',
          textAlign: 'center',
          alignItems: 'center',
          justifyContent: 'center',
        }}
      >
        Hello world!
      </div>
    )
    {
      width: 1200,
      height: 600,
    }
  )
}

  ImageResponse는 경로 처리기 및 파일 기반 메타데이터를 포함하여 다른 Next.js API와 잘 통합된다. 예를 들어 opengraph-image.tsx 파일에서 ImageResponse를 사용하여 빌드 시 또는 요청 시 동적으로 오픈 그래프 이미지를 생성할 수 있다.

  ImageResponse는 flexbox 및 절대 위치 지정, 사용자 지정 글꼴, 텍스트 줄 바꿈 가운데 맞춤 및 중첩 이미지를 비롯한 일반적인 CSS 속성을 지원한다.

 

  • JSON-LD

  JSON-LD는 콘텐츠를 이해하기 위해 검색 엔진에서 사용할 수 있는 구조화된 데이터 양식이다. 예를 들어 사람, 이벤트, 조직, 영화, 책, 조리법 및 기타 여러 유형의 엔터티를 설명하는 데 사용할 수 있다.

  JSON-LD에 대한 현재 권장 사항은 구조화된 데이터를 layout.js 또는 page.js 컴포넌트에서 <script> 태그로 렌더링 하는 것이다.

// app/products/[id]/page.tsx

export default async function Page({ params }) {
  const product = await getProduct(params.id)
  
  const jsonLd = {
    '@context': 'https://schema.org',
    '@type': Product,
    name: product.name,
    image: product.iamge,
    description: product.description,
  }
  
  return (
    <section>
      {/* Add JSON-LD to your page */}
      <script
        type="application/Id+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLD) }}
      />
      {/* ... */}
    </section>
  )
}

  Google용 리치 결과 테스트 또는 일반 스키마 마크업 검사기로 구조화된 데이터의 유효성을 검사하고 테스트할 수 있다. schema-dts와 같은 커뮤니티 패키지를 사용하여 TypeScript로 JSON-LD를 입력할 수 있다.

import { Product, WithContext } from 'schema-dts';

const jsonLd: WithContext<Product> = {
  '@context': 'https://schema.org',
  '@type': 'Product',
  name: 'Next.js Sticker',
  image: 'https://nextjs.org/imgs/sticker.png',
  description: 'Dynamic at the speed of static',
}

'Next.js' 카테고리의 다른 글

Next.js 9-7 Lazy Loading  (0) 2023.06.15
Next.js 9-6 Static Assets  (0) 2023.06.14
Next.js 9-4 Script Optimization  (0) 2023.06.09
Next.js 9-3 Font Optimization  (0) 2023.06.08
Next.js 11-13 Routing Internationalization  (1) 2023.06.08