DevLog:-)

NEXT.js 메타데이터, 오픈그래이프 적용기(1) - 다이나믹 메타데이터 적용 본문

카테고리 없음

NEXT.js 메타데이터, 오픈그래이프 적용기(1) - 다이나믹 메타데이터 적용

hyeon200 2024. 7. 11. 14:34
반응형

Next.js는 서버 사이드 렌더링(SSR)과 정적 사이트 생성(SSG)을 손쉽게 구현할 수 있도록 도와줍니다.

Next.js를 사용할 때 중요한 요소 중 하나가 메타데이터(metadata)인데요. 

최근 투표 플랫폼 Picky 프로젝트에서 Metadata를 적용하게 되어 적용기를 작성하게 되었습니다!

Metadata란?

메타데이터(metadata)는 웹 페이지에 대한 정보를 설명하는 데이터입니다. 보통 HTML 문서의 <head> 태그 내에 포함되며, 웹 브라우저와 검색 엔진이 페이지를 이해하고 적절히 처리할 수 있도록 도와줍니다. 대표적인 메타데이터 요소로는 title, meta 태그의 description, keywords 속성 등이 있습니다.

 

Metadata와 SEO

SEO(검색 엔진 최적화)는 웹사이트가 검색 엔진 결과 페이지에서 더 높은 순위를 차지하게 하는 일련의 전략과 기술입니다. 메타데이터는 SEO의 중요한 구성 요소 중 하나로, 검색 엔진이 페이지의 내용을 이해하고 인덱싱하는 데 도움을 줍니다. 적절한 메타데이터 설정을 통해 검색 결과에서의 가시성을 높일 수 있습니다.

 

Open Graph란?

Open Graph는 Facebook에서 개발한 프로토콜로, 웹 페이지가 소셜 미디어 플랫폼에서 어떻게 보여질지를 정의합니다. Open Graph 메타데이터는 다음과 같이 소셜 미디어에서 공유될 때 웹 페이지의 제목, 설명, 이미지 등을 지정할 수 있습니다.

Dynamic Meta란?

Dynamic Meta는 웹 페이지의 메타데이터를 동적으로 생성하는 기술을 의미합니다.

예를 들어, 블로그 포스트와 같은 콘텐츠에서는 각 포스트마다 다른 제목, 설명, 이미지를 메타데이터로 설정해야 합니다. 이를 위해 서버 사이드 렌더링을 사용하거나 클라이언트 사이드에서 동적으로 메타데이터를 설정할 수 있습니다.

저는 picky가 게시글 서비스인 만큼 페이지별로 다른 정보를 제공할 수 있도록 동적 메타데이터를 적용했습니다. 

 

 

이제 Next.js에 Metadata를 적용해 볼까요?

 

Next.js에서 Static Metadata 설정

Next.js를 사용하지 않았던 프로젝트에서는 주로 index.html 파일의 <head> 태그 내에 메타데이터를 설정했습니다.

이와 달리 Next.js에서는 메타데이터 설정에 아주 용이한 기능을 갖추고 있습니다.

바로 metadata 객체를 활용하는 것입니다! Next.js 공식 문서를 참고하면 쉽게 이해할 수 있습니다.

 

Next.js에서는 layout.js나 page.js 파일에 metadata 객체를 이용하여 정적 메타데이터를 설정할 수 있습니다. 다음은 정적 메타데이터를 설정하는 간단한 예시입니다.

// layout.js | page.tsx
import type { Metadata } from 'next';
 
export const metadata: Metadata = {
  title: 'picky',
  description: '투표를 통한 고민 해결 커뮤니티'
};
 
export default function Page() {
  return <div>Content</div>;
}

Dynamic Metadata 설정

Next.js의 metadata 객체를 이용해 동적 메타데이터도 쉽게 구현할 수 있습니다.

metadata 객체를 반환하는 generateMetadata 함수를 활용하는 것입니다.

generateMetadata 함수를 사용하면 페이지별 데이터를 받아와서 동적으로 메타데이터를 설정할 수 있습니다.

// app/products/[id]/page.tsx
import type { 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> {
  // 라우트 파라미터 읽기
  const id = params.id;
 
  // 데이터 가져오기
  const product = await fetch(`https://api.example.com/products/${id}`).then((res) => res.json());
 
  // 부모 메타데이터를 확장
  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) {
  return <div>Product Details</div>;
}

 

picky프로젝트에 Metadata 적용하기

1. Static Metadata

저는 위에 내용을 바탕으로 프로젝트에 Metadata 생성 유틸리티 함수를 구현해 적극 활용했습니다!

정적 메타데이터를 getMetadata 함수를 구현하여 layout.tsx에 불러왔습니다. 

// app/layout.tsx
import { getMetadata } from '../utils/getMetadata';

export const metadata = getMetadata();
// utils/getMetadata.ts
import type { Metadata } from 'next';

export const getMetadata = (metadataProps?: GetMetadataProps) => {
  const { title, description, asPath, image, icon } = metadataProps || {};

  const TITLE = title ? `${title} | picky` : META.title;
  const DESCRIPTION = description || META.description;
  const PAGE_URL = asPath ? META.url + asPath : META.url;
  const IMAGE = image || META.image;
  const ICON = icon || META.icon;

  const metadata: Metadata = {
    metadataBase: new URL(META.url),
    alternates: {
      canonical: PAGE_URL,
    },
    manifest: '/manifest.json',
    title: TITLE,
    description: DESCRIPTION,
    keywords: [...META.keyword],
    icons: {
      icon: ICON,
    },
    openGraph: {
      title: TITLE,
      description: DESCRIPTION,
      siteName: TITLE,
      locale: 'ko_KR',
      type: 'website',
      url: PAGE_URL,
      images: {
        url: IMAGE,
      },
    },
    twitter: {
      title: TITLE,
      description: DESCRIPTION,
      images: {
        url: IMAGE,
      },
    },
  };

  return metadata;
};
// META는 상수화된 메타정보 객체입니다.

이처럼 layout.tsx에서 Metadata를 따로 유틸함수로 분리하여 layout.tsx의 코드 길이를 단축하고 기능별 유지보수 측면에서도 효율적이었습니다. 또한 getMetaData 유틸리티 함수를 재활용하여 추후  동적 메타데이터 유틸리티 함수도 쉽게 구현할 수 있었습니다.



2. Dynamic Metadata

정적 메타 정보를 담고 있는 getMetadata를 불러와 getGenerateMetadata를 만들어 동적 메타데이터를 설정했습니다.

게시글 페이지 url에 params에서 postId를 가져오고 그에 맞는 데이터를 받아와 메타데이터에 게시글 별로 동적으로 적용되도록 했습니다.

// utils/getGenerateMetadata.ts
const RESULT_MESSAGE = '투표 결과를 확인하세요.';
const VOTE_MESSAGE = 'picky에서 투표해보세요';

export const getGenerateMetadata = () => async ({ params }: { params: { postId: string } }) => {
  try {
    const postId = params.postId;
    const response = await getVoteDetail(postId);

    if (!response || !response.body) {
      return;
    }

    const { voteTitle, hasVoted, voteOptions, terminated: isTerminated } = response.body;
    const thumbnailImageUrl = voteOptions?.map(({ voteOptionImageUrl }) => voteOptionImageUrl).filter(url => url)[0];
    const title = `${voteTitle}`;
    const description = hasVoted || isTerminated ? RESULT_MESSAGE : VOTE_MESSAGE;

    return getMetadata({
      title,
      description,
      asPath: `/result/${postId}`,
      image: thumbnailImageUrl,
    });
  } catch (error) {
    console.error('Failed to generate metadata:', error);
    return;
  }
};

동적으로 데이터를 받아 Open Graph 이미지를 게시글 이미지로 변경하고, 투표 진행 중인 게시글이라면 'picky에서 투표해보세요'를, 투표 종료 게시글이라면 '투표 결과를 확인하세요'를 띄워 더 나은 사용자 경험에 신경썼습니다.

 

이와 같이 Next.js에서는 metadata 객체를 이용해 정적 및 동적 메타데이터를 쉽게 설정할 수 있습니다. 이를 통해 SEO와 소셜 미디어에서의 콘텐츠 미리보기 최적화를 할 수 있습니다.

Next.js의 새로운 문법이 처음에는 낯설었지만 익숙해지면서 훨씬 효율적으로 메타데이터를 관리할 수 있었고 Next.js의 장점을 다시 체감하게 된 계기가 되었습니다.

 

 

 

추가적으로 메타데이터 작업을 할때 번거로운 배포 과정 없이 

브라우저 확장 프로그램과 미리보기 웹사이트를 적절히 활용하여 빠른 검증과 개발이 가능합니다!

자세한 내용은 다음 포스팅에서 확인하실 수 있습니다!

 

 

NEXT.js 메타데이터, 오픈그래이프 적용기(2) - local환경에서 확인하는 법

이번 투표플랫폼 Picky프로젝트에 메타데이터를 적용하면서 난감했던 부분은 바로 잘 적용되었는지 검증하는 과정이었습니다. sns 공유상 메타데이터가 잘 적용되었는지 확인하기 위해서는 배포

developer-gaeppu.tistory.com

 

반응형