사이트맵이 필요한데 자동으로 만들어지는거 없나?
이 블로그에도 구글에 노출되기 위해 사이트맵이 필요해서 적용하기로했다.(사실 기본적인거지만)
이 사이트맵이란 새로운 포스트가 등록될때마다 업데이트를 해줘야한다. 그래서 다른 블로그들은 이걸 어떻게 처리하고있는지 찾아봤다.
대부분의 경우 sitemap.xml을 생성해주는 스크립트가 있는데 문제는 그걸 직접 실행시켜서 /public/sitemap.xml
파일을 새로 만들어내는 방법이었다.
vercel이나 gatsby 의 경우 어떤식으로 동작하는지는 모르겠지만 이 블로그 같은 경우 aws에 배포를한 상태고 /public
경로에있는 내용들을 업데이트 하려면 매번 새로 빌드를하고 다시 배포를 해야하는 상황이다. 그래서 nextjs에서 자동으로 동적인 사이트맵을 생성해주는 기능이 필요로했고 다음 같은 두가지 방법을 찾았다.
먼저 이 방법은 getServerSideProps의 res 객체를 이용한 일종의 트릭이다.
const Sitemap = () => {};
export const getServerSideProps = ({ res }) => {
const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<!-- We'll render the URLs for our sitemap here. -->
</urlset>
`;
res.setHeader("Content-Type", "text/xml");
res.write(sitemap);
res.end();
return {
props: {},
};
};
export default Sitemap;
/pages
폴더에 sitemap.xml.js 파일을 생성한다.res
객체를 이용해 xml을 클라이언트로 보낸다.getServerSideProps의 res
객체는 nodejs 환경의 response 객체이다. 그래서 next 서버에서 nodejs 백엔드 서버 처럼 xml파일 자체를 응답하는게 가능하다. 따라서 사용자가 /sitemap.xml 경로에 접근한다면 렌더링된 페이지가 아닌 동적으로 생성된 xml파일을 받게 된다.
실제 nextjs에서 사이트맵을 생성해주는 next-sitemap 이라는 패키지의 소스코드 도 똑같은 방식으로 구현되어있다.
//next-sitemap 패키지의 동적 xml 구현부분
import type { GetServerSidePropsContext } from 'next'
/**
* Send XML response
* @param ctx
* @param content
* @returns
*/
export const withXMLResponse = (
ctx: GetServerSidePropsContext,
content: string
) => {
if (ctx?.res) {
const { res } = ctx
// Set header
res.setHeader('Content-Type', 'text/xml')
// Write the sitemap context to resonse
res.write(content)
// End response
res.end()
}
// Empty props
return {
props: {},
}
}
이 방법은 vercel 에서 직접 소개하고 있는 방법이다. nextjs 에서 /api 로 시작하는 경로는 next 서버 자체에서 api를 제공하기 위해 사용된다. next 자체가 마치 api 엔드포인트처럼 동작하도록 만들수있는데 아무튼 이 방법도 결국은 res 객체를 사용하는 방법이다.
next에서 api 경로를 작성하기 위해선 반드시 handler 함수를 내보내야한다. 이 핸들러 파라미터에 req 와 res 객체가 있다. getServerSideProps 방법과 마찬가지로 이 핸들러 안에서 동적으로 xml 파일을 생성후 res 객체로 응답해준다.
export default function handler(req, res) {
res.statusCode = 200
res.setHeader('Content-Type', 'text/xml')
// Instructing the Vercel edge to cache the file
res.setHeader('Cache-control', 'stale-while-revalidate, s-maxage=3600')
// generate sitemap here
const xml = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>http://www.example.com/foo.html</loc>
<lastmod>2021-01-01</lastmod>
</url>
</urlset>`
res.end(xml)
}
/sitemap.xml 주소로 연결하기 위해 next.config.js 파일에 rewrites 규칙을 작성해준다.
module.exports = {
async rewrites() {
return [
{
source: '/sitemap.xml',
destination: '/api/sitemap',
},
]
},
}
이렇게 설정해두면 사용자가 /sitemap.xml
에 접근했을때 실제로는 /api/*
경로의 응답을 보게된다.