GatsbyJSでMarkdownを書くと,ファイル名がslug (URLの一部)になってしまいます.ファイル名は日本語にしたいが,slugは英語にしたい.また,slugを指定しない場合は通常通りファイル名から自動生成したい.これを実現する設定について説明します.
TL;DR
以下のように node.frontmatter.slug || を gatsby-node.js の exports.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コマンドの使い方を学べ,勉強になりました.
本記事が少しでも参考になれば幸いです.
