-
Notifications
You must be signed in to change notification settings - Fork 5
🏷 SEO: Sitemap & Meta tag
Knoticle 서비스에는 유저들이 작성한 다양한 글이 존재한다. 이러한 글들이 검색 엔진에 노출되도록, 검색 엔진 최적화(SEO)를 하는 것이 주요한 목표 중 하나다. 본문에서는 SEO를 위해 Sitemap과 Meta tag를 작성한 과정에 대해 소개하도록 하겠다.
Google의 SEO 기본 가이드 에 따르면 다음과 같은 부분들을 개선할 수 있다.
- 사이트맵 등록하기
- 메타 태그 작성하기
- robots.txt
웹사이트에서 구글이나 네이버와 같은 검색 엔진에 색인할 모든 페이지를 나열한 XML 파일
Google의 SEO 기본 가이드에 따르면…
내 사이트가 Google에서 검색되도록 하기 위한 첫 번째 단계는 Google이 사이트를 발견할 수 있도록 하는 것입니다. 이때는 사이트맵을 제출하는 것이 가장 좋습니다. 사이트맵은 사이트에 있는 파일로서 새 페이지나 변경된 페이지가 있을 때 이를 검색엔진에 알려 줍니다.
-
Googlebot 및 기타 웹 크롤러는 한 페이지에서 다른 페이지로 연결되는 링크를 따라 이동하여 웹을 크롤링하는데, 다른 사이트가 링크되어 있지 않으면 페이지를 찾지 못할 수 있다.
-
사이트맵은 검색엔진 크롤러에 어떤 페이지가 있는지 알려주어, 검색엔진이 찾기 어려운 페이지도 문제없이 크롤링될 수 있게 한다.
-
내 사이트는 사이트맵이 필요할까?
-
매우 큰 사이트거나, 연결되는 외부 링크가 많지 않고, 사이트끼리 잘 연결되지 않은 상태라면 사이트맵이 필요할 수 있다.
-
반면 크기가 작은 사이트거나, 내부적으로 긴밀히 연결된 사이트라면 사이트맵을 사용하지 않아도 된다.
-
🤔 Knoticle의 사이트맵을 생성하려면
-
사용자가 작성한 글 페이지들을 모두 사이트맵에 등록해야한다.
글의 주소가
knoticle.app/viewer/{책 id}/{글 id}
와 같이 구성되어 있다. -
글들이 계속 업데이트 되기 때문에 sitemap을 동적으로 생성해야 한다.
존재하는
{책 id}/{글 id}
를 DB에서 일정 시간 간격으로 받아와서 sitemap을 생성해야 한다.
→
next-sitemap
이라는 라이브러리 사용 (링크)
- DB로부터 생성해야 하는 페이지 정보들을 받아온다.
-
사용자가 작성한 글 페이지의 주소를 완성하기 위해서는
책 id
와글 id
가 필요하다. -
Knoticle 서비스에서는
scraps
테이블에책 id
와글 id
가 저장되어 있다.→ 그 중 글이 원본인 아이템(즉,
원본 책 id
와글 id
의 조합)만 받아오도록 했다. 검색엔진에 원본 글만 잡히는 것이 맞다고 생각했다.
-
받아온 정보들로 페이지마다 field를 생성한다.
field는 다음과 같은 형태로 구성되어 있는데,
loc: `${process.env.NEXT_PUBLIC_CLIENT_URL}/viewer/${scrap.book_id}/${scrap.article_id}`, changefreq: 'daily', priority: '1.0', lastmod,
- changefreq: 사이트가 얼마나 자주 바뀌는지에 대한 정보. 검색 엔진한테 대략 어느 주기로 페이지의 변화를 체크해야 하는지 알려준다.
- priority: 사이트 내에서 페이지들의 상대적인 우선 순위를 나타낸다.
→ 하지만 Google 검색 센터에 따르면, Google에서는
<priority>
및<changefreq>
값을 무시한다고 한다. -
생성된 fields로 sitemap.xml을 구성한다.
코드는 다음과 같다.
// pages/sitemap.xml.tsx
import { GetServerSidePropsContext } from 'next';
import { getServerSideSitemap } from 'next-sitemap';
import { getScrapsApi } from '@apis/scrapApi';
export default function SiteMapXML() {
return <></>;
}
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
const scraps = await getScrapsApi();
const lastmod = new Date().toISOString();
const defaultFields = [
{
loc: `${process.env.NEXT_PUBLIC_CLIENT_URL}`,
changefreq: 'daily',
priority: '1.0',
lastmod,
},
];
const scrapFields = scraps.map((scrap: { book_id: number; article_id: number }) => ({
loc: `${process.env.NEXT_PUBLIC_CLIENT_URL}/viewer/${scrap.book_id}/${scrap.article_id}`,
changefreq: 'daily',
priority: '1.0',
lastmod,
}));
const fields = [...defaultFields, ...scrapFields];
return getServerSideSitemap(context, fields);
};
-
knoticle.app/sitemap.xml로 들어가면 잘 생성된 것을 확인할 수 있다.
- 검색엔진 크롤러가 사이트맵을 찾을 수 있도록 검색엔진별로 제출하는 것이 필요하다.
- 구글: 구글 서치 콘솔을 이용하여 제출 가능
- 네이버: 네이버 서치 어드바이저의 웹마스터 도구를 통해 사이트맵 제출 가능
-
<meta>
태그는 해당 문서에 대한 정보인 **메타데이터(metadata)**를 정의할 때 사용한다:
<base>
,<link>
,<script>
,<style>
,<title>
요소와 같은 다른 메타데이터 관련 요소들이 나타낼 수 없는 다양한 종류의 메타데이터를 제공할 때 사용되며, 이렇게 제공된 정보는 브라우저나 검색 엔진, 다른 웹 서비스에서 사용하게 된다
-
SEO를 위해서는 메타 태그를 작성해주어야 한다. 구글의 SEO 기본 가이드에 다음과 같은 내용이 있다.
메타 설명 태그는 중요합니다. Google에서 설명 메타 태그를 Google 검색결과에서 페이지의 스니펫으로 사용할 수 있기 때문입니다.
-
여기서 스니펫이란 검색 결과가 표시되는 부분이다.
: 타이틀은
<title>
태그와 관련되어 있고, 아래 설명은<meta name=”description”>
과 관련되어 있다.
-
구글 공식 문서에 따르면, 구글에서 인식하는 메타 태그에는 다음이 있다.
-
<meta name="description" content="A description of the page" />
: 간단한 페이지 설명
-
<meta name="viewport" content="...">
: 휴대기기에서 페이지를 렌더링하는 방법을 브라우저에 알리는 태그. 이 태그를 사용하면 페이지가 모바일 친화적이라는 사실을 Google에 알릴 수 있다.
-
<meta http-equiv="Content-Type" content="...; charset=..." />
<meta charset="..." >
: 페이지의 콘텐츠 유형과 문자 집합을 정의하는 태그. 가능한 경우 Unicode/UTF-8을 사용하는 것이 좋다.
따라서,
-
<title>
및<meta name=”description”>
태그를 페이지마다 다르게 생성하자. - 그 외
open graph
에 관련된 메타 태그도 페이지마다 다르게 지정해주자.
- 사이트를 공유했을 때 사이트에 대한 정보를 미리보기로 확인할 수 있도록, 미리보기에 담을 메타데이터를 표준화하기 위한 프로토콜
-
뷰어페이지에 적용하기
-
getServerSideProps
로 article 데이터 받아오기
export const getServerSideProps: GetServerSideProps = async (context) => { const [bookId, articleId] = context.query.data as string[]; const article = await getArticleApi(articleId); return { props: { article } }; };
-
getServerSideProps
는 서버에서 동작하는 코드이므로, 함수 내부에서 next/router를 사용할 수가 없다. 처음에 사용했더니 다음과 같은 오류가 발생했다. -
공식 문서에 따르면 context를 사용해야 한다. context 객체 내의 query에서 dynamic route의 query parameter를 가져올 수 있다.
- 가져온 아티클 정보로 title 및 메타 태그 완성하기
import Head from 'next/head'; interface ViewerHeadProps { articleTitle: string; articleContent: string; } export default function ViewerHead({ articleTitle, articleContent }: ViewerHeadProps) { return ( <Head> <title>{articleTitle}</title> <meta name="description" content={articleContent.slice(0, 150)} /> <meta name="viewport" content="initial-scale=1.0, width=device-width" /> <meta property="og:title" content={articleTitle} /> <meta property="og:description" content={articleContent.slice(0, 150)} /> <meta property="og:type" content="website" /> <meta property="og:url" content="https://www.knoticle.app" /> <meta property="og:image" content="https://kr.object.ncloudstorage.com/j027/knoticle.png" /> </Head> ); }
-
-
open graph 적용 결과
아래와 같이 knoticle 서비스의 글 링크를 복사해서 붙여넣으면 다음과 같이 표현된다.
og:title
에 넣은 글 제목과,og:description
에 넣은 글 본문의 일부를 확인할 수 있다.
- robots.txt 파일은 크롤러가 사이트의 어느 부분에 액세스할 수 있는지에 관한 규칙이 포함된 간단한 텍스트 파일
-
robots.txt 파일을 사용하여 크롤링 트래픽을 관리하거나(서버에 Google 크롤러의 요청으로 인한 과부하가 발생할 것으로 생각되는 경우) 사이트에서 중요하지 않은 페이지 또는 비슷한 페이지의 크롤링을 방지할 수 있다.
- 웹페이지가 Google에 표시되는 것을 방지하기 위한 메커니즘이 아니다.
-
sitemap.xml의 위치를 등록하여 sitemap이 어딨는지 알려준다.
- Knoticle 서비스에서 글을 쓸 수 있는 에디터 페이지(editor)와 검색 페이지(search)는 검색 엔진에 노출되지 않았으면 했기에 아래와 같이 작성하였다.
# *
User-agent: *
Allow: /
# Disallow
User-agent: *
Disallow: /editor
Disallow: /search
# Host
Host: https://www.knoticle.app/
# Sitemaps
Sitemap: https://www.knoticle.app/sitemap.xml # Index sitemap
-
Lighthouse SEO 점수가 80 → 97까지 상승
-
이전
-
SEO를 위한 방법들 적용 후
-
-
Lighthouse SEO 점수를 높이는 것은 어렵지 않았다. title 및 meta 태그를 작성한 것이 결정적이었던 것 같다.
-
점수를 높이는 게 쉬운 만큼, 웬만한 사이트들은 높은 점수를 유지하고 있을텐데 그 중에서도 검색 엔진에 잘 노출되게 하려면 더 다양한 방법을 시도해봐야 할 것 같다.
참고 자료
사이트맵이란 무엇인가요? | Google 검색 센터 | 문서 | Google Developers
The Importance of The XML Sitemap Priority and Changefreq Tags
사이트맵 만들기부터 제출하기: 쉬운 단계별 가이드 | TBWA 데이터랩
Data Fetching: getServerSideProps | Next.js
Robots.txt Sitemap: Add Your Sitemap To Your Robots.txt File