Gatsby Starter BlogでMDXを使用できるようにする
2021-06-10 23:55
Gatsby Starter BlogはMarkdown(.md)で記事が書けるようになっているが、 簡単な分、複雑なことをするには向いてない。そこでMDXを使用して記事を書けるように変更する。
MDXとは
MDXとは、Markdown文書の中にJSXも書ける形式のこと。拡張子はmdx
。
つまりReactコンポーネントを使って記事を書けたりするので、
普通のMarkdownではできない(めんどくさい)処理を書いたりすることもできる。
Gatsby開発チームの人が作ってるのでGatsby製サイトとの親和性は高いが、Next.jsなどGatsby以外でも使える。
参照元
Gatsbyの公式ブログでMDXに替える方法が丁寧に説明されているので大体はこれに従う。
How to convert an existing Gatsby blog to use MDX
導入手順
必要なパッケージの導入
MDXを使用するために必要なパッケージを以下コマンドで導入する。
npm install gatsby-plugin-mdx gatsby-plugin-feed-mdx @mdx-js/mdx @mdx-js/react
次に、gatsby-config.jsを変更する。
gatsby-transformer-remark
をgatsby-plugin-mdx
に置き換える- オプションを
gatsby-plugin-mdx
に合わせて書き換える&追加する
- オプションを
gatsby-plugin-feed
をgatsby-plugin-feed-mdx
に置き換える
module.exports = {
// ...
plugins: [
// ...
{
- resolve: `gatsby-transformer-remark`,
+ resolve: `gatsby-plugin-mdx`,
options: {
+ extensions: [`.mdx`, `.md`],
- plugins: [
+ gatsbyRemarkPlugins: [
{
resolve: `gatsby-remark-images`,
options: {
maxWidth: 630,
},
},
// ...
]
}
},
- `gatsby-plugin-feed`,
+ `gatsby-plugin-feed-mdx`,
// ...
]
}
不要になるパッケージの削除
MDXを使用する方法に変更するため、元々導入されていたMarkdown読み込み用のパッケージは削除する。
npm uninstall gatsby-transformer-remark gatsby-plugin-feed
ビルド処理の修正
プラグイン変更に伴い、以下の書き換えが必要になる。
allMarkdownRemark
→allMdx
MarkdownRemark
→Mdx
markdownRemark
→mdx
- GraphQLで取得するフィールドを
html
からbody
に - 記事の展開を
MDXRenderer
に
書き換え対象は以下。
- gatsby-node.js
- src/pages/index.js
- src/templates/blog-post.js
順に修正していく。
gatsby-node.js
Gatsby Starter Blogなら4箇所あるはず。
exports.createPages = async ({ graphql, actions, reporter }) => {
// ...
const result = await graphql(
`
{
- allMarkdownRemark(
+ allMdx(
...
`
// ...
- const posts = result.data.allMarkdownRemark.nodes
+ const posts = result.data.allMdx.nodes
// ...
exports.onCreateNode = ({ node, actions, getNode }) => {
const { createNodeField } = actions
- if (node.internal.type === `MarkdownRemark`) {
+ if (node.internal.type === `Mdx`) {
const value = createFilePath({ node, getNode })
// ...
exports.createSchemaCustomization = ({ actions }) => {
const { createTypes } = actions
createTypes(`
// ...
- type MarkdownRemark implements Node {
+ type Mdx implements Node {
frontmatter: Frontmatter
fields: Fields
}
...
`
// ...
src/pages/index.js
Gatsby Starter Blogなら2箇所あるはず。
// ...
const BlogIndex = ({ data, location }) => {
const siteTitle = data.site.siteMetadata?.title || `Title`
- const posts = data.allMarkdownRemark.nodes
+ const posts = data.allMdx.nodes
// ...
}
// ...
export const pageQuery = graphql`
query {
...
- allMarkdownRemark(sort: { fields: [frontmatter___date], order: DESC })
+ allMdx(sort: { fields: [frontmatter___date], order: DESC })
...
`
src/templates/blog-post.js
Gatsby Starter Blogなら7箇所あるはず。
// ...
+ import { MDXRenderer } from "gatsby-plugin-mdx"
const BlogPostTemplate = ({ data, location }) => {
- const post = data.markdownRemark
+ const post = data.mdx
// ...
return (
<Layout location={location} title={siteTitle}>
// ...
<article
className="blog-post"
itemScope
itemType="http://schema.org/Article"
>
<header>
<h1 itemProp="headline">{post.frontmatter.title}</h1>
<p>{post.frontmatter.date}</p>
</header>
- <section
- dangerouslySetInnerHTML={{ __html: post.html }}
- itemProp="articleBody"
- />
+ <MDXRenderer itemProp="articleBody">{post.body}</MDXRenderer>
// ...
export const pageQuery = graphql`
query BlogPostBySlug(
$id: String!
$previousPostId: String
$nextPostId: String
) {
site {
siteMetadata {
title
}
}
- markdownRemark(id: { eq: $id }) {
+ mdx(id: { eq: $id }) {
id
excerpt(pruneLength: 160)
- html
+ body
frontmatter {
title
date(formatString: "MMMM DD, YYYY")
description
}
}
- previous: markdownRemark(id: { eq: $previousPostId }) {
+ previous: mdx(id: { eq: $previousPostId }) {
fields {
slug
}
frontmatter {
title
}
}
- next: markdownRemark(id: { eq: $nextPostId }) {
+ next: mdx(id: { eq: $nextPostId }) {
fields {
slug
}
frontmatter {
title
}
}
}
`
動作の確認
上記の設定を行ったら、MDXを使用できるようになっている。
例えば以下のようなmdxファイルで記事を作成してgatsby develop
してみる。
---
title: MDX!
date: 2021-06-09
description: "A post showing MDX in action"
---
This is a post showing MDX in action. This starter now comes with MDX out-of-the-box!
```js
// you can write JSX in your Markdown!
<button>test</button>
これで記事が作成されていればOK。
(補足)frontmatterを読み込めるようにする
frontmatterとは、Markdownファイルの先頭に書く記事のタイトルとかの情報。
公式サイトの説明によると、 MDXだと以下のような感じでfrontmatterを読み込んだりができるらしい。
---
title: Building with Gatsby
author: Jay Gatsby
---
<h1>{props.pageContext.frontmatter.title}</h1>
<span>{props.pageContext.frontmatter.author}</span>
(Blog post content, components, etc.)
しかしこれが実際に試してみるとうまくいかない模様。
参考: GatsbyのMDXファイルでfrontmatterが参照できない問題
上記サイトに説明が書かれているため詳細は省くけど、どうやらsrc/page
にMDXファイルを置いていれば
前述のようなprops.pageContent.frontmatter.***
の形式で読み込めるらしいが、
そうじゃないとうまくいかないらしい。
Gatsby Starter Blogではcontent/blog
の中にMarkdownファイルを置いて記事として読ませているので、
読み込むことができない。
解決するためには、frontmatterをあらかじめ渡しておけばいい。
blog-post.js内にある、先ほど編集した記事を展開するコンポーネントMDXRenderer
のところに
プロパティとしてfrontmatter
を明示的に示す。以下のような感じ。
- <MDXRenderer itemProp="articleBody">{post.body}</MDXRenderer>
+ <MDXRenderer frontmatter={post.frontmatter} itemProp="articleBody">{post.body}</MDXRenderer>
これで、こんな感じに書くとfrontmatterが使える。
---
title: テスト記事
date: 2021-06-10 23:55:09
description:
---
* <b>title: {props.frontmatter.title}</b>
* <i>date: {props.frontmatter.date}</i>
先人の知恵は偉大。