[Next.js] SEO최적화를 위해 Schema.org 사용해서 데이터 구조화하기

Eunhye Kim·2023년 12월 14일
1

Next.js

목록 보기
2/14
post-thumbnail

SEO 최적화를 위해 Schema.org를 사용해서 데이터 구조화를 했다.

Schema.org를 사용하면 검색 엔진이 웹 페이지의 콘텐츠를 더 잘 이해하고 색인화할 수 있다. 이는 검색 결과의 정확성과 품질을 향상시키는데 도움이 된다

이번 글은 Schema.org 적용하면서 생긴 문제점과, 그걸 어떻게 해결했는지도 같이 설명해보겠다.

예시 데이터

export const BlogData = [
  {
    id: 'Blog1',
    title: 'title1',
    content: [
      {
        id: 1,
        subTitle: 'subTitle1',
        desc: 'desc1',
      },
      {
        id: 2,
        subTitle: 'subTitle2',
        desc: 'desc2',
      },
    ],
  },
  {
    id: 'Blog2',
    title: 'title2',
    content: [
      {
        id: 1,
        subTitle: 'subTitle1',
        desc: 'desc1',
      },
      {
        id: 2,
        subTitle: 'subTitle2',
        desc: 'desc2',
      },
    ],
  },
    ...
];

예시 코드

import React from 'react';
import { useRouter } from 'next/router';
import { BlogData } from './data';

const BlogDetailPage = () => {
  const router = useRouter();
  const { id } = router.query;
  const blogPost = BlogData.find((post) => post.id === id);

  return (
    <section>
      <div>
        <h2>{blogPost?.title}</h2>
         <ul>
          {blogPost?.content.map((item) => (
            <li key={item.id}>
              <h2>{item.subTitle}</h2>
              <p>{item.desc}</p>
            </li>
          ))}
         </ul>
      </div>
    </section>
  );
};

export default BlogDetailPage;

출력된 화면


문제점

출력된 화면에서는 데이터 요소들이 잘 나타났지만 '페이지 소스보기'에서 subTitle1을 검색하면 요소가 안 나타난다.
분명 화면에는 잘 나오는데 소스보기에는 안 나타났고 blogPost의 다른 데이터 또한 모두 소스보기에서는 확인이 안 됐다.

해결

서치와 추측의 결과 '페이지 소스 보기'에서는 일반적으로 초기 서버 측 렌더링 결과만 표시되므로, 클라이언트 측에서 동적으로 생성된 내용은 나타나지 않을 수 있다.
그래서 해결책으로 서버에서 데이터를 미리 렌더링하면 된다.

나는 getServerSideProps를 사용해서 서버 측 렌더링을 했다.
*Next.js14의 경우는 getServerSideProps를 지원하지 않으므로 다른 방법이 필요하다.


수정 된 코드


import React from 'react';
import { useRouter } from 'next/router';
import { BlogData } from './data';

const BlogDetailPage = ({blogPost}) => {

  return (
    <section>
      <div>
        <h2>{blogPost?.title}</h2>
         <ul>
          {blogPost?.content.map((item) => (
            <li key={item.id}>
              <h2>{item.subTitle}</h2>
              <p>{item.desc}</p>
            </li>
          ))}
         </ul>
      </div>
    </section>
  );
};

export async function getServerSideProps({ params }) {
  const { id } = params
  const blogPost = BlogData.find((item) => item.id === id)

  return {
    props: {
      blogPost,
    },
  }
}


export default BlogDetailPage;

소스보기를 보면 이번에는 검색이 잘 되는걸 볼 수 있다.


Schema.org 적용

그럼 이제 문제가 해결이 됐으니, Schema.org를 적용해보겠다.

적용할 코드

const structuredData = {
  '@context': 'https://schema.org',
  '@type': 'BlogPosting',
   name: item.subTitle,
   articleBody: item.desc,
}
          
return (
   <script
     type="application/ld+json"
     dangerouslySetInnerHTML={{ __html: JSON.stringify(structuredData) }}
   />
)

추가된 코드


import React from 'react';
import { useRouter } from 'next/router';
import { BlogData } from './data';

const BlogDetailPage = ({blogPost}) => {

  return (
    <section>
      <div>
        <h2>{blogPost?.title}</h2>
         <ul>
          {blogPost?.content.map((item) => {
          const structuredData = {
            '@context': 'https://schema.org',
            '@type': 'BlogPosting',
            name: item.subTitle,
            articleBody: item.desc,
          }

          
           return(
             <>
            	<li key={item.id}>
                  <h2>{item.subTitle}</h2>
              	  <p>{item.desc}</p>
            	</li>
                <script
                  type="application/ld+json"
                  dangerouslySetInnerHTML={{ __html: JSON.stringify(structuredData) }}
              />
			</>
		   )
  		  })}
         </ul>
      </div>
    </section>
  );
};

export async function getServerSideProps({ params }) {
  const { id } = params
  const blogPost = BlogData.find((item) => item.id === id)

  return {
    props: {
      blogPost,
    },
  }
}


export default BlogDetailPage;

이렇게 작성을 하고 구조화된 데이터 테스트에서 확인해보면

이렇게 구조화된 데이터를 확인할 수 있다.



[참고]
https://stackoverflow.com/questions/61073587/view-source-not-displaying-dynamic-content
https://blog.outsider.ne.kr/1214
https://wordlift.io/blog/en/entity/schema-org/

profile
개발에 몰두하며 성장하는 도중에 얻은 인사이트에 희열을 느낍니다.

0개의 댓글