공부공부/Next.js 공식문서

[next.js 공식문서] 19. Metadata

고생쨩 2024. 3. 3. 21:51
728x90

next.js 13버전 때 학습내용 정리 문서로 현재와 다름 주의

Metadata

SEO를 위한 메타 데이터 API

  • 구성 기반 메타데이터: 정적 메타데이터 객체 또는 동적 생성 메타데이터 함수를 layout.js 또는 page.js 파일로 내보냅니다.
  • 파일 기반 메타데이터: 정적 또는 동적으로 생성된 특수 파일을 경로 세그먼트에 추가합니다.

정적 메타데이터

// layout.tsx / page.tsx
import { Metadata } from 'next';
 
export const metadata: Metadata = {
  title: '...',
  description: '...',
};
 
export default function Page() {}

동적 메터데이터

// 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(`https://.../${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) {}

파일 기반 메타데이터

  • favicon.ico, apple-icon.jpg, icon.jpg
  • opengraph-image.jpg 및 twitter-image.jpg
  • robots.txt
  • sitemap.xml

정적 메타데이터를 사용하거나 프로그래밍 방식으로 생성할 수 있음

동작

파일 기반 메타데이터가 더 높은 우선순위를 가지며 모든 구성 기반 메타데이터보다 우선합니다.

기본 필드

경로가 메타데이터를 정의하지 않더라도 항상 추가되는 두 가지 기본 메타 태그가 있습니다:

  • 메타 문자 집합 태그는 웹사이트의 문자 인코딩을 설정합니다.
  • 메타 뷰포트 태그는 웹사이트의 뷰포트 너비와 배율을 설정하여 다양한 장치에 맞게 조정합니다.
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />

순서

  1. app/layout.tsx (루트 레이아웃)
  2. app/blog/layout.tsx (하위 레이아웃)
  3. app/blog/[slug]/page.tsx (페이지)

중복

중복 시 마지막 순서것으로 출력됨

동적 이미지 생성

ImageResponse를 사용함. ImageResponse는 엣지 런타임에서 동작함.

import { ImageResponse } from 'next/server';
 
export const runtime = 'edge';
 
export async function GET() {
  return new ImageResponse(
    (
      <div
        style={{
          fontSize: 128,
          background: 'white',
          width: '100%',
          height: '100%',
          display: 'flex',
          textAlign: 'center',
          alignItems: 'center',
          justifyContent: 'center',
        }}
      >
        Hello world!
      </div>
    ),
    {
      width: 1200,
      height: 600,
    },
  );
}
  • 엣지 런타임만 지원되므로 별도 엣지 서버 구성 필요.
  • 500kb 용량제한 있음.
  • 기본 node 런타임 사용시 imagemagick(npm install gm)나 node-gd를 사용하는 방법이 있음
  • 비디오의 경우 ffmpeg 사용

JSON-LD

검색엔진용
<script> 태그로 렌더링하면됨.

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.image,
    description: product.description,
  };
 
  return (
    <section>
      {/* Add JSON-LD to your page */}
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
      />
      {/* ... */}
    </section>
  );
}
// schema-dts를 사용하여 아래처럼도 구성가능
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.',
};

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.