[Next.js] Next.js에서 XML Sitemap 만들기
XML Sitemap이란?
사이트맵은 사이트의 페이지, 동영상 및 기타 파일들에 대한 정보를 제공하는 파일입니다. 누구한테 제공하냐면 사이트를 읽고 검색 엔진에 보여주는 크롤러에게 제공합니다. 사이트맵을 만드는 이유는 크롤러가 내 사이트를 크롤링하기 전에 어떤 페이지와 어떤 컨텐츠가 있는지 요약 정보를 제공해 줌으로써 좀 더 효율적인 크롤링을 가능하게 해 주기 때문입니다.
구글 공식 문서에 따르면, 사이트맵이 필요한 경우는 다음과 같습니다.
- 사이트의 규모가 큰 경우
- 만든지 얼마 안 됐거나 외부 링크가 적은 경우
- 페이지 간 연결이 잘 안 되어있거나 개별적으로 존재하는 페이지가 많은 경우
- 비디오나 이미지처럼 미디어 컨텐츠가 많거나 구글 뉴스에 나온 경우
사이트맵이 잘 작성되어 있는 경우 크롤링이나 검색 순위에도 영향이 있다고 하니 검색 노출이 중요한 웹사이트라면 만들어 놓는 게 여러모로 좋다고 생각합니다.
XML Sitemap에서 사용하는 태그들
1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>http://www.example.com/</loc>
<lastmod>2023-01-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
</urlset>
<urlset>
- 필수 입력 사항
<url>
을 감싸는 부모 요소입니다.
<url>
- 필수 입력 사항
- url 관련 정보들을 감싸는 부모 요소입니다.
<log>
- 필수 입력 사항
- url 주소를 적는 요소입니다.
<lastmod>
- 선택 입력 사항
- 마지막으로 수정된 날짜를 적는 요소입니다.
- w3 표준시로 작성되어야 합니다.
<changefreq>
- 선택 입력 사항
- 얼마나 자주 컨텐츠가 변경되는지 적는 요소입니다.
- 유효한 값으로 always, hourly, daily, weekly, monthly, yearly, never가 있습니다.
- 방문할 때마다 바뀌는 부분이 있으면 “always”에 해당되고, 앞으로 바뀔 일이 절대 없으면 “never”에 해당됩니다.
- 어느 주기로 크롤링을 해야 될지 기준을 제공해 주지만, 그렇다고 무조건 이 기준대로 크롤링이 되는 건 아닙니다.
<priority>
- 선택 입력 사항
- 내 사이트에서 어떤 걸 우선 순위로 두어야 될지를 정하는 요소입니다.
- 기본값은 0.5, 최소 값은 0.0, 최댓값은 1.0입니다.
<changefreq>
와 마찬가지로 우선순위를 크롤러에 제공할 뿐, 무조건 우선 순위대로 크롤링이 되는 건 아닙니다.- 내 사이트 내에서의 상대적인 우선 순위를 정하는 거기 때문에 전부 1로 넣는다고 해서 좋을 건 없습니다.
Next.js에서 사이트맵 만들기
Next.js에서 사이트맵을 만드는 방법은 두 가지가 있습니다.
정적 사이트맵
내 사이트에 페이지가 많지 않거나, 페이지 수가 제한되어 있는 경우 정적 사이트맵을 만들어서 /public
폴더 안에 넣어주기만 하면 됩니다. 정적 사이트맵은 직접 제작할 수도 있지만, 자동으로 제작해 주는 사이트도 많이 있어서 이런 사이트들을 이용하면 손쉽게 제작할 수 있습니다.
위 도메인에 접속해 네모 박스에 url만 입력하면 자동으로 사이트맵을 만들어 줍니다.
동적 사이트맵
동적 사이트맵은 다른 페이지들과 동일하게 getServerSideProps로 만들 수 있습니다. 먼저 /pages
폴더 안에 sitemap.xml.js, 타입스크립트를 사용 중이라면 sitemap.xml.tsx 파일을 만들어 줍니다. 그 후 getServerSideProps 안에 API를 호출해 원하는 데이터를 불러와 동적으로 넣어주면 됩니다.
sitemap.xml.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
function generateSiteMap(posts: any) {
return `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<!-- 정적인 페이지는 수동으로 입력 -->
<url>
<loc>https://taedonn.tistory.com</loc>
<lastmod>2023-12-05T15:39:57+09:00</lastmod>
<priority>1.0</priority>
</url>
.
.
.
<!-- 동적인 페이지는 map() 함수를 통해 distribute -->
${
posts.map((post: any) => {
return `
<url>
<loc>https://taedonn.tistory.com/${post.id}</loc>
</url>
`;
}).join('')
}
</urlset>`;
}
function SiteMap() {
// 비워두고 getServerSideProps에서 res.write()를 통해 브라우저에 XML을 보낸다.
}
export async function getServerSideProps({ res }: { res: any }) {
// API를 호출해 데이터를 받아온다.
const request = await fetch("API 주소");
const posts = await request.json();
// 사이트맵 구조를 받아온다.
const sitemap = generateSiteMap(posts);
// sitemap 변수에 저장한 XML 사이트맵을 SiteMap 컴포넌트에 내보낸다.
res.setHeader("Content-Type", "text/xml");
res.write(sitemap);
res.end();
return {
props: {},
}
}
export default function SiteMap;
이렇게 해서 완성된 사이트맵. 아래 동적인 부분은 데이터가 추가될 때마다 반영되어 보입니다.
https://taedonn.tistory.com/sitemap.xml