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를 적용해보겠다.
적용할 코드
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/