@senspond
>
이번 글에는 React 기반으로 만들어진 NextJs 프레임워크에서 동적으로 Sitemap 만드는 방법에 대해서 정리해보고 현재 발견한 문제점에 대해서 적어보려고 합니다.
이번 글에는 React 기반으로 만들어진 NextJs 프레임워크에서 동적으로 Sitemap 만드는 방법에 대해서 정리해보고 현재 발견한 문제점에 대해서 적어보려고 합니다.
사이트맵은 사이트에 있는 페이지, 동영상 및 기타 파일과 그 관계에 관한 정보를 제공하는 파일입니다. Google과 같은 검색엔진은 이 파일을 읽고 사이트를 더 효율적으로 크롤링합니다. 사이트맵은 내가 사이트에서 중요하다고 생각하는 페이지와 파일을 Google에 알리고 중요한 관련 정보를 제공합니다. 관련 정보의 예로는 페이지가 마지막으로 업데이트된 시간, 페이지의 대체 언어 버전이 있습니다.
- 출처 : 구글 검색센터 (https://developers.google.com/search/docs/crawling-indexing/sitemaps/overview?hl=ko)
웹 크롤링 Bot들이 웹사이트들을 크롤링하여 검색엔진에 색인을 하게 되는데, 해당 사이트를 크롤링 할때 좀더 효율적으로 할 수 있도록 제공해주는 것으로 이해할 수 있다. 블로그가 외부에 잘 검색유입이 되려면 일단 각종 포털사이트 검색엔진에 효과적으로 색인이 되어야 하는데, 그만큼 검색엔진 최적화(SEO)에 있어서 중요하다.
import { getSortedPostsData } from "../lib/posts";
function generateSiteMap(data) {
const sitemap = `
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${siteMapData
.map((item) => {
return `
<url>
<loc>${item.url}</loc>
<lastmod>${item.lastModified}</lastmod>
</url>
`
})
.join("")}
</urlset>
`
return sitemap;
}
export async function getServerSideProps({ res }) {
const data = await SitemapService.getSitemap();
const sitemap = generateSiteMap(data)
res.setHeader("Content-Type", "text/xml");
res.write(sitemap);
res.end();
return {
props: {},
},
revalidate : 10, // 재검증 시간
}
export default function SiteMap() {}
기존에 page 기반 라우팅 방식을 사용하던 nextjs에서 쓰던 방식이다. 현재 rgbitcode 웹 사이트는 NextJs 13이상 App라우팅 방식을 쓰게 되면서 위의 방식은 사용하지 못하였다.
이 방법은 vercel 에 안내되어 있는 방법이라고 한다. api/sitemap/route.ts 에 다음과 같이 작성한다.
import { MetadataRoute } from 'next';
import {SitemapService} from "@/middleware/services/sitemap/SitemapService";
import { NextRequest, NextResponse } from "next/server";
export async function GET(req : NextRequest, res : NextResponse) {
const now = new Date().toISOString();
const data : MetadataRoute.Sitemap = await SitemapService.getSitemap();
const siteMapData = [
{
url: `${process.env.NEXT_PUBLIC_API_URL}`,
lastModified: now,
},
{
url: `${process.env.NEXT_PUBLIC_API_URL}/blog`,
lastModified: now,
},
...data
]
const sitemap = `
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${siteMapData
.map((item) => {
return `
<url>
<loc>${item.url}</loc>
<lastmod>${item.lastModified}</lastmod>
</url>
`
})
.join("")}
</urlset>
`
return new Response(sitemap, {
status: 200,
headers: {
"Cache-control": "public, s-maxage=86400, stale-while-revalidate",
"content-type": "application/xml",
},
})
}
SitemapService.getSitemap()은 DB에서 조회하여 데이터를 가져오도록 만들었다.
/api/sitemap 을 요청하면 xml 로 응답하게 되는데,
next.config.js 설정파일에서 rewrites 로 /sitemap.xml 로 요청하면 /api/sitemap 의 응답을 돌려주도록 설정하면 된다.
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: false,
async rewrites() {
return [
{
source : "/sitemap.xml",
destination : "/api/sitemap"
}
]
}
}
module.exports = nextConfig
nextjs 홈페이지에 안내되어 있는 최신 방법이다. nextjs 13버전 이상에서 page기반 라우팅 방식 대신 App 라우팅 방식을 사용하게 되면 이렇게 간단하게 가능하다.
import { MetadataRoute } from 'next';
import {SitemapService} from "@/middleware/services/sitemap/SitemapService";
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const now = new Date().toISOString();
const data: MetadataRoute.Sitemap = await SitemapService.getSitemap();
return [
{
url: `${process.env.NEXT_PUBLIC_API_URL}`,
lastModified: now,
},
{
url: `${process.env.NEXT_PUBLIC_API_URL}/blog`,
lastModified: now,
},
...data
];
}
이전 버전의 next.js(page)에서는 사이트 맵의 재검증 시간을 설정하고 적용이 됬던 것으로 알고 있는데, 왜 App 버전에서는 제대로 동작되지 않는 문제점이 발견됬다.
필자의 경우 npm run dev 로 실행 할때는 컨텐츠가 추가 됬을때 캐시를 적용하고 revalidate를 주게 되면 일정시간이 흐르면 동적으로 사이트 맵이 변경되는 것을 확인 할 수 있었는데, 빌드(npm run build) 후 시작(npm run start) 하게 되면 적용되지 않았다.
export class SitemapService{
static getSitemap(): Promise<any>{
return FetchApi.getRequest(REQUEST.BACKEND_SERVER as string, "/v1/sitemap", null, {
cache : "force-cache",
next : {
revalidate: 10
}
});
}
}
next cache를 적용하지 않고 "no-store" 옵션으로 조회할때마다 DB에서 불러오도록 설정해도 개발서버에서는 컨텐츠가 변경될때마다 사이트맵이 변동되었지만, 빌드 하고 실행하보면 빌드시점의 사이트맵으로 고정되었다.
export class SitemapService{
static getSitemap(): Promise<any>{
return FetchApi.get(REQUEST.BACKEND_SERVER as string, "/v1/sitemap", null, "no-store")
}
}
rgbitcode 웹 사이트에는 방법2,방법3 모두 사용해봤지만 빌드시점에 만들어진 sitemap이 변동되지 않았다.
현재 App 라우팅 방식의 버전에서 정말 동적으로 사이트 맵이 업데이트 되도록 만드려면 다른 방법이 필요해 보인다.
nextjs 개발팀에서 패치가 필요할 것 같습니다.
안녕하세요. Red, Green, Blue 가 만나 새로운 세상을 만들어 나가겠다는 이상을 가진 개발자의 개인공간입니다.
현재글에서 작성자가 발행한 같은 카테고리내 이전, 다음 글들을 보여줍니다
@senspond
>