Gatsby製のブログで、コードハイライトにはプラグインとしてgatsby-remark-prismjs
を使っている
特に設定などせず使っていたが、調べたら行番号指定でのハイライトや、シェル表示など色々なものがあるようだったのでローカルで試していた
しかし、prism-coy
のテーマが良くないのか組み合わせが悪いのか、結構意図と反する表示になることが多く、CSSをがっつり修正することにした
その際に、このケースが載っている記事はあったっけな…というのを毎度探すのがたいへんだったので、どうせならある程度のユースケースを網羅しているサンプル用の記事を用意してそこを見ればOKというような状態にしたい
あわよくばVisualRegressionTestまで行えれば良さそうではということでサンプル用の記事を作ることにした
やりたいことは下記
- Markdownでサンプル用の記事を作成したい、既存の記事と同様
- 記事一覧やArchiveには載らないようにしたい
調べたらsource filesystemで複数ソースを扱うことができるよう
参考
Gatsbyで2種類のマークダウンファイルの区別する方法Takumon Blog
まさにやろうとしているのはこれだった、以降で自身でも実際にやったことを残していく
ディレクトリ分割してsource filesystemで読み込む
通常の記事をblog
、今回作成するサンプル用の記事をsample
として扱う
ディレクトリ
- blog
content/blog/entries/
以下にMarkdownファイル
- sample
content/sample/samples/
以下にMarkdownファイル
sourceの読み込み
- gatsby-config.ts
plugins以下の設定にsample用の設定を加える
{ resolve: `gatsby-source-filesystem`, options: { path: `${__dirname}/content/blog`, name: `blog`, }, }, + { + resolve: `gatsby-source-filesystem`, + options: { + path: `${__dirname}/content/sample`, + name: `sample`, + }, + },
以降name
を元に区別をしていく
GatsbyのNodeにフィールド追加する
Gatsbyではビルドプロセス中に、NodeといってMarkdownファイル、画像ファイル、ファイルなどのデータの単位を生成している
そのNodeに対してGraphQLでクエリを投げて取得したデータを元に色々な処理や表示をさせることができるという仕組みになっている
各種プラグインではこのNodeに対して特定のソースではこのNodeを生成するという処理をしている
そして、Nodeの生成時に呼び出されるAPIとしてonCreateNode
という物があり、生成されるNodeに対して独自の処理を加えることができる
よくあるのはフィールド追加などかな
今回はMarkdownRemarkのNodeにcollection
というフィールドを追加した
- gatsby-node.ts(一部抜粋)
export const onCreateNode: GatsbyNode["onCreateNode"] = ({ node, actions, getNode }) => { const { createNodeField } = actions if (node.internal.type === `MarkdownRemark` && node.parent) { const slug = createFilePath({ node, getNode }) createNodeField({ name: `slug`, node, value: slug, }) const parent = getNode(node.parent) createNodeField({ name: "collection", node, value: parent?.sourceInstanceName, }) } }
MarkdownRemarkのparent
はFileのNodeでFileにはsourceInstanceName
というフィールドがあり、そこに前節で設定したblog
、sample
などが設定されている
GraphQLでFileに対してクエリして確認した
- Fileへのクエリ
query File { allFile { nodes { sourceInstanceName name } } }
- クエリ結果一部抜粋
{ "data": { "allFile": { "nodes": [ { "sourceInstanceName": "blog", "name": "algolia_mock_with_msw" }, { "sourceInstanceName": "sample", "name": "prismjs" } ] } } }
collection
というフィールド名でその値を設定する
これでMarkdownRemarkのNodeでblog
、sample
の区別ができるようになる
フィールド追加後、MarkdownRemarkにクエリした結果の一部抜粋
query AllMarkdown { allMarkdownRemark { edges { node { fields { slug collection } } } } }
{ "node": { "fields": { "slug": "/entries/vscode_terminal_profile/", "collection": "blog" } } }, { "node": { "fields": { "slug": "/samples/prismjs/", "collection": "sample" } } },
OKそう
GraphQLクエリでフィルタリングする
前節でMarkdownRemarkのNodeにcollection
フィールドを追加した
今までは想定として単一種のMarkdownソースを扱うようにGraphQLのクエリを書いていたため、ブログ記事を想定している各画面ではブログ記事orサンプルを区別する必要がある
ということで、すべてのGraphQLクエリに変更が必要…
といっても今回のケースはそんなに多くなかったのでひとつずつ書き換えた
- 例
allMarkdownRemark(sort: { frontmatter: { date: DESC } }, filter: { fields: { collection: { eq: "blog" } } }) { edges { node { ..... ..... .....
MarkdownRemarkに対してfilter
でfields: { collection: {eq: "blog" } }
というように取得したいcollectionを指定する
実際に一覧ではクエリで絞ってサンプル記事を表示しないようにした
まとめ
Gatsbyのブログサイトで、通常の記事とサンプル記事を区別して扱えるようにした
- gatsby-source-filesystemで複数のMarkdownソースを管理
- GatsbyのNodeにフィールドを追加して後続プロセスで区別できるような値を設定
- GraphQLクエリでブログ記事とサンプル用の記事の出し分け
この辺のGatsbyのAPIや、source、transformerなどを調べるとかなりわかった気になる(理解度は深まったはず)、色々できそうだなと感じたのでアイデア考えるのが楽しくなる
最後に、コードハイライトのCSSも修正しているけど、実際の差分は下記PullRequestに
コードハイライト、Markdownの見た目調整 by swfz · Pull Request #1694 · swfz/til