Theme:

블로그: 메타 태그 직접 관리하기에 대해 "왜?"라고 물으면 답할 수 있으신가요?

\n\n> 블로그: 메타 태그 직접 관리하기에 대해 "왜?"라고 물으면 답할 수 있으신가요?\n블로그를 만들면서 SEO를 완전히 무시할 수는 없었습니다. 아무리 좋은 글을 써도 검색에 안 잡히면 아무도 안 읽으니까요.

가장 기본적인 건 메타 태그입니다. <title>, og:title, description 같은 태그를 페이지마다 다르게 넣어줘야 검색 엔진이나 카카오톡 같은 데서 미리보기가 제대로 나옵니다.


react-helmet-async는 안 됩니다

리액트에서 메타 태그를 관리하는 가장 유명한 라이브러리는 react-helmet-async입니다. 당연히 이걸 쓰려고 했는데, 설치부터 막혔습니다.

BASH
npm install react-helmet-async
PLAINTEXT
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree

react-helmet-async 2.0.5
  └── ✕ unmet peer react@"^16.6.0 || ^17.0.0 || ^18.0.0": found 19.0.0

React 19를 지원하지 않습니다. 찾아보니 React 19부터는 JSX 안에서 <title>이나 <meta> 같은 태그를 쓰면 프레임워크가 알아서 <head>로 올려주는 기능이 추가됐더라고요. 그래서 react-helmet-async 쪽에서 아직 React 19 대응을 안 한 것 같습니다.

그냥 직접 만들기로 했습니다.


관리할 메타 태그 정리

블로그에서 챙겨야 할 메타 태그를 정리하면 크게 세 종류입니다.

기본 메타 태그

  • title — 브라우저 탭, 검색 결과에 표시
  • description — 페이지 설명
  • theme-color — 모바일 브라우저 상단 색상
  • article:published_time — 글 작성 시각
  • article:modified_time — 글 수정 시각

Open Graph (OG)

  • og:typewebsite 또는 article
  • og:title, og:description — 카카오톡, 슬랙 등에서 링크 미리보기

Twitter Card

  • twitter:cardsummary_large_image
  • twitter:title, twitter:description

전부 비슷비슷한 값이 들어가는데, 각 플랫폼이 보는 태그가 달라서 중복이더라도 다 넣어야 합니다.


SeoHelper 컴포넌트

페이지마다 메타 태그를 일일이 쓰면 코드가 지저분해지니까, SeoHelper라는 컴포넌트로 감쌌습니다.

JSX
const SeoHelper = ({
    title,
    description,
    path,
    type = 'website',
    publishedTime,
    modifiedTime,
}) => {
    const url = `https://bak-libra26.co.kr${path}`;

    return (
        <>
            {/* 기본 */}
            <title>{title}</title>
            <meta name="author" content="bak-libra26" />
            <meta name="description" content={description} />
            <meta name="theme-color" content="#0a0a0f" />
            {publishedTime && <meta property="article:published_time" content={publishedTime} />}
            {modifiedTime && <meta property="article:modified_time" content={modifiedTime} />}

            {/* OG */}
            <meta property="og:type" content={type} />
            <meta property="og:title" content={title} />
            <meta property="og:description" content={description} />
            <meta property="og:url" content={url} />

            {/* Twitter */}
            <meta name="twitter:card" content="summary_large_image" />
            <meta name="twitter:title" content={title} />
            <meta name="twitter:description" content={description} />
        </>
    );
};

React 19에서는 이렇게 JSX로 <title>이나 <meta>를 쓰면 자동으로 <head>에 들어갑니다. react-helmet-async가 없어도 되는 이유입니다.


페이지별 적용

각 페이지 컴포넌트의 return문 안에 <SeoHelper />를 넣으면 됩니다.

JSX
// 글 상세 페이지
const PostDetailPage = () => {
    const post = ...;

    return (
        <>
            <SeoHelper
                title={`${post.title} - bak-libra26`}
                description={post.summary}
                path={`/posts/${post.path}`}
                type="article"
                publishedTime={post.createdDate.toISOString()}
                modifiedTime={post.lastModifiedDate.toISOString()}
            />
            <article>
                ...
            </article>
        </>
    );
};
JSX
// 글 목록 페이지
<SeoHelper
    title="Posts — sim.junghun"
    description="개발 블로그 글 목록"
    path="/posts"
/>
JSX
// 홈페이지
<SeoHelper
    title="sim.junghun — backend engineer"
    description="개발 블로그"
    path="/"
/>

페이지마다 title이랑 description만 바꿔서 넣으면 되니까 사용은 간단합니다. 페이지 수가 적어서 이 정도 수동 작업은 부담이 없고요.


JSON-LD 구조화 데이터

메타 태그만으로도 기본적인 SEO는 되는데, 구글에서는 JSON-LD 형태의 구조화 데이터도 권장합니다. SeoHelper에 이것도 포함시켰습니다.

JSX
// article 타입일 때
const jsonLd = {
    '@context': 'https://schema.org',
    '@type': 'BlogPosting',
    headline: title,
    description: description,
    datePublished: publishedTime,
    dateModified: modifiedTime,
    author: {
        '@type': 'Person',
        name: 'sim.junghun',
    },
};

이걸 <script type="application/ld+json">으로 페이지에 삽입하면 구글이 글의 구조를 더 잘 이해합니다. 검색 결과에 발행일이 표시된다든지 하는 효과가 있습니다.


솔직한 소감

react-helmet-async가 안 돼서 처음엔 좀 당황했는데, 직접 만들어보니 오히려 더 깔끔합니다. React 19의 메타데이터 호이스팅 덕분에 별도 Provider를 감쌀 필요도 없고, 그냥 JSX 쓰듯이 쓰면 되니까요.

다만 이건 SPA 한계상, 자바스크립트가 실행되어야 메타 태그가 들어간다는 문제가 있습니다. 크롤러가 JS를 실행하지 않으면 빈 페이지로 인식할 수 있죠. 이 문제는 다음 글에서 프리렌더링으로 해결합니다.

댓글 로딩 중...