ブラウザ版のNotionを便利にするNewtion
Next.jsで静的なXMLサイトマップを作る【外部ライブラリ不要】の絵文字

Next.jsで静的なXMLサイトマップを作る【外部ライブラリ不要】

2022-04-24

2022-04-24

はじめに

Next.js 廃れないでほしいこふです。

動的なサイト(TwitterZenn など)ではない静的なサイトにおいて SSGStatic 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.jsgetStaticProps で動かし、pages/sitemap.tsx という場所で作成します。


自分の考えるメリット

  • ユーザーが見るサイトマップを作る準備ができる
  • package.json を変更しなくて良い
  • Next.jsAPI Routesを使用しない(Vercel でなくても使える!)

デメリット

  • 動的サイトには使えない

ソースコード

src/pages/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} /> {/* 自分でエラー用のコンポーネント使う */} </> ) } export default Page export const getStaticProps = async () => { await generateSitemapXml() return { props: {} } }
src/lib/sitemap.ts
import { 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.ts
import { 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.txt
Sitemap: https://example.com/sitemap.xml

さいごに

これでブログ・日記サイトをクローラーに認知してもらう仕組みができました。

src/pages/sitemap.xml に人間が見るサイトマップを作る時の手間を減らせるのでおすすめです。

これをGoogle Search Consoleなどで送信してあげれば OK!

参考

関連記事


アバター

こふ

情報通信を専攻している大学生です。大学・趣味・アルバイトでプログラムを書いています。ITサービス・文章を創作することが好きです。

このブログについて

共有する