メインコンテンツまでスキップ

GatsbyでMarkdownから slug を指定するための設定

· 約6分

GatsbyJSでMarkdownを書くと,ファイル名がslug (URLの一部)になってしまいます.ファイル名は日本語にしたいが,slugは英語にしたい.また,slugを指定しない場合は通常通りファイル名から自動生成したい.これを実現する設定について説明します.

TL;DR

以下のように node.frontmatter.slug || gatsby-node.jsexports.onCreateNode 内で対応する箇所に追加する.

exports.onCreateNode = ({ node, actions, getNode }) => {
const { createNodeField } = actions

if (node.internal.type === `MarkdownRemark`) {
// If specified, `slug` field of frontmatter is prioritized
const value = node.frontmatter.slug || createFilePath({ node, getNode }) // highlight-line

createNodeField({
name: `slug`,
node,
value,
})
}
}

その上で, slug を指定したいポストには,frontmatter (---で囲まれた部分) に slug: /SOME_SLUG の形で slug を指定する.

ここで, slug として/で始まらない文字列を指定すると,リンクが正しく表示されない場合が発生することがあります(対処法は後述).

解説

Gatsby でどのようにして Markdown から ページや slug が生成されているかについては,hththtさんの記事 Gatsbyノート3(slug/pageの生成) が分かりやすいです.
デフォルトでは createFilePath 関数によってファイル名をもとに slug を生成していますが,||演算子を使って frontmatter 部分に slug が定義されている場合はそれを用い,そうでなければデフォルト通り生成する,という処理を実現しています.

どんなときに便利か

ブログのポストにあたる Markdown のファイル名を日本語にしたいが,slug は英語を自分で設定したい,ということが可能になります.
また,Markdown を 2022/06/06/title.md のように 年月日のフォルダで管理しているが,slug は https://example.com/title にしたい,という場合にも,同じ部分をいじれば可能です.
この場合だと,createFilePath の出力を適切に split して取り出すことになると思います.

slug が/から始まるよう強制する

上記のonCreateNode内を修正しても良いですが,/から始まらないような slug の指定が存在した場合コミットができないように,Git のフックを設定する方法を紹介します.
.git/hooks/pre-commit (存在しなければ作成) に以下を記載すると,このチェックが実現できます.

#!/bin/sh

# Confirm every .md file which has a valid slug, if any, in its frontmatter.
# Slug should start with '/' and be longer than just '/'.
for file in `find content/blog -name '*.md'`; do
match=$(sed -n '/---/{p; :loop n; p; /---/q; b loop}' $file | grep 'slug:' | grep -E -v 'slug: /.+')
if [ "$match" != "" ]; then
echo "Error: Custom slug should start with / and include other character(s) after that."
echo "Check this file: " $file
exit 1
fi
done
  • find によって /content/blog 以下の.mdで終わるファイルについて for ループを回しています.
  • sed によって frontmatter 部分 (---で囲まれた最初の箇所) のみを取り出しています.
    • / でパターンを区切っています.
    • --- を見つけたら,{}で囲まれた部分を実行します.
    • p は行を表示します.
    • :loop でラベルloopをつけます.
    • n; で次の行に移ります.
    • /---/q;---というパターンを見つけたら loop を quit します.
    • b loop でループラベル loop にジャンプします.
    • -n は,その他の行は表示しない,というオプションです.
  • grep によって slug: を含む行のうち,slug の中身が / で始まらない行や/のみで終わっている行を取り出しています.
  • もしこれが ""でない場合正しくないので,異常を報告しファイル名を表示してステータスコード1で終了します.

まとめ

今回は,Gatsby でスラッグ(slug)を指定する方法を紹介しました.
個人的には,Git のフックを利用する部分やsedコマンドの使い方を学べ,勉強になりました.
本記事が少しでも参考になれば幸いです.