Next.jsで静的なXMLサイトマップを作る【外部ライブラリ不要】
2022-04-24
2022-04-24
はじめに
Next.js
廃れないでほしいこふです。
動的なサイト(Twitter
、Zenn
など)ではない静的なサイトにおいて SSG
(Static Site Generation
)時にスクリプトを動かしてサイトマップを作ります。
用途は、以下のような不規則にページが増えないサイトです。
- 個人・企業のブログ
- 個人の日記サイト
環境
Next.js
以外の外部ライブラリは用いません。例えばnextjs-sitemap
というライブラリなど。
❯ node -v v16.14.0
package.json{ "dependencies": { ... "react": "^17.0.2", "react-dom": "^17.0.2", "next": "^12.1.5", // getStaticPropsが使えるならOK ... }, "devDependencies": { ... "typescript": "4.5.4" ... } }
方針
関数を作ってサイトマップの文字列を作成し、ファイルとして書き込む、です。
そのスクリプトは Next.js
の getStaticProps
で動かし、pages/sitemap.tsx
という場所で作成します。
自分の考えるメリット
- ユーザーが見るサイトマップを作る準備ができる
package.json
を変更しなくて良いNext.js
のAPI Routes
を使用しない(Vercel でなくても使える!)
デメリット
- 動的サイトには使えない
ソースコード
src/pages/sitemap.tsximport { generateSitemapXml } from '@/libs/sitemap' // 下で出てきます import { NextPage } from 'next' import DefaultErrorPage from 'next/error' import Head from 'next/head' const Page: NextPage = () => { return ( <> <Head> <meta name="robots" content="noindex" /> </Head> <DefaultErrorPage statusCode={404} /> {/* 自分でエラー用のコンポーネント使う */} </> ) } export default Page export const getStaticProps = async () => { await generateSitemapXml() return { props: {} } }
src/lib/sitemap.tsimport { abouts } from '@/constants/footer' import { FrontURL } from '@/constants/urls' import fs from 'fs' export const generateSitemapXml = async () => { let xml = `<?xml version="1.0" encoding="UTF-8"?>` xml += `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">` const nowJST = new Date( Date.now() + (new Date().getTimezoneOffset() + 9 * 60) * 60 * 1000 ) const lastmod = nowJST.toISOString().split('T')[0] // about site abouts.forEach((p) => { xml += ` <url> <loc>${FrontURL}${p.href}</loc> <lastmod>${lastmod}</lastmod> <changefreq>monthly</changefreq> </url> ` }) // legal ... // contact ... // blog ... xml += `</urlset>` fs.writeFileSync('public/sitemap.xml', xml) return null }
ソースコードの解説
sitemap.tsx
import { generateSitemapXml } from '@/libs/sitemap' // 下で出てきます import { NextPage } from 'next' import DefaultErrorPage from 'next/error' import Head from 'next/head'
必要なライブラリをインポートします。
const Page: NextPage = () => { return ( <> <Head> <meta name="robots" content="noindex" /> </Head> <DefaultErrorPage statusCode={404} /> {/* 自分でエラー用のコンポーネント使う */} </> ) }
大事な点が 2 つあります。
- クローラーに index させない
- 404 エラーのページを見せる(ユーザーのため)
ユーザーが見るサイトマップを作らないなら、です。
もしユーザーも見るサイトマップページ(WordPress
でよくあるやつ)を作るなら、index させ、エラーではなく表示したいコンポーネントを作れば良いだけです。
export default Page export const getStaticProps = async () => { await generateSitemapXml() return { props: {} } }
ポイントは getStaticProps
でサイトマップを作る関数である generateSitemapXml
を呼び出すということ。
そうすることで package.json
などでコードを追加する必要なく関数をビルド時に一回だけ呼び出すことができます。
sitemap.ts
src/lib/sitemap.tsimport { abouts } from '@/constants/footer' import { FrontURL } from '@/constants/urls' import fs from 'fs'
必要なライブラリ、定数をインポートします。
export const generateSitemapXml = async () => { let xml = `<?xml version="1.0" encoding="UTF-8"?>` xml += `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">` const nowJST = new Date( Date.now() + (new Date().getTimezoneOffset() + 9 * 60) * 60 * 1000 ) const lastmod = nowJST.toISOString().split('T')[0] // about site abouts.forEach((p) => { xml += ` <url> <loc>${FrontURL}${p.href}</loc> <lastmod>${lastmod}</lastmod> <changefreq>monthly</changefreq> </url> ` }) // legal ... // contact ... // blog ... xml += `</urlset>` fs.writeFileSync('public/sitemap.xml', xml) return null }
関数本体です、少し長いですがやってることはシンプルです。
ポイントは以下の通り
xml
の構造にあるように文字列を加算するfs
を使ってファイルとして書き込むpublic
以下に配置する(だれでもアクセスできる場所)
lastmod
ですが、最後に編集した日付としてビルド時を指定しています。
ブログであれば、その情報に紐づいた日付を lastmod
にすれば OK です。
余談ですが、abouts
という変数は別のディレクトリからインポートしています。
どんなやり方であれ、ページのリンクを取得して生成する仕組みがあれば問題ありません。
自分は、値を一箇所で管理するようにしているので、表示名(label
)やリンク先のパス(href
)も別の場所で管理しています。(href
よりpath
の方が良いかも。。。)
export const abouts: LinksType = [ { label: AboutName, href: AboutPath, }, { label: FaqsName, href: FaqsPath, }, { label: ChangelogName, href: ChangelogPath, }, { label: LoadmapName, href: LoadmapPath, }, ]
robots.txt
以下のようにクローラーにわかってもらえるよう指定します。
robots.txtSitemap: https://example.com/sitemap.xml
さいごに
これでブログ・日記サイトをクローラーに認知してもらう仕組みができました。
src/pages/sitemap.xml
に人間が見るサイトマップを作る時の手間を減らせるのでおすすめです。
これをGoogle Search Console
などで送信してあげれば OK!