GatsbyでMarkdown内で独自コンポーネントを作成して使用する


はじめに

こんにちは。雨雲レーダー見ていて、ギリギリ降らないなと普段してたら、一気に降ってきて、久々に全力ダッシュしました。無謀にもびしょ濡れになりました、筆者です

さて、今回はContentfulで管理しているブログの記事内に、独自コンポーネントをContentfulから挿入したいので、その対応を行ったので、記事にしました。
参考になれば幸いです!

GatsbyでMarkdown内でコンポーネントを使う

以下を使って実装していきます。

1. プラグインをインストール

npmの方はこちら↓

$ npm install gatsby-remark-component rehype-react

yarnの方はこちら

$ yarn add gatsby-remark-component rehype-react

インストール有無を確認

念のためインストールできているか確認

$ npm ls --depth=0 | grep -P "rehype-react|gatsby-remark-component"

├── [email protected]
├── [email protected]

2. gatsby-config.jsを編集

gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: `gatsby-transformer-remark`,
      options: {
        plugins: [
+           `gatsby-remark-component`,
        ],
      },
    },
  ],
};

3. 独自コンポーネント作成

画像とタイトルだけの記事のアイテムをイメージしています。

src/components/CustomComponent.js
import React from 'react'

const CustomComponent = props => (
  <div>
      <p>Custom Component!!!!</p>
  </div>
)

export default CustomComponent

4. 3で作成したコンポーネントの読み込み

src/components/PageBody.js
  import React from 'react'
+ import CustomComponent from "../components/CustomComponent"
+ import RehypeReact from "rehype-react"

  ...
  ...
  ...

  const PageBody = props => {
+   const renderAst = new RehypeReact({
+     createElement: React.createElement,
+     components: { "custom-component": CustomComponent }
+   }).Compiler

    return (
-    <Body
-      dangerouslySetInnerHTML={{ __html: props.body.childMarkdownRemark.html }}
-    />
+    <Body>
+      {renderAst(props.body.childMarkdownRemark.htmlAst)}
+    </Body>
    )
  }

  export default PageBody

5. 4でrenderAstに渡しているhtmlAstをGraphQLの取得項目に追加

src/templates/post.js
  export const query = graphql`
    query($slug: String!) {
      contentfulPost(slug: { eq: $slug }) {
        title
        slug
        metaDescription {
          internal {
            content
          }
        }
        publishDate(formatString: "MMMM DD, YYYY")
        publishDateISO: publishDate(formatString: "YYYY-MM-DD")
        tags {
          title
          id
          slug
        }
        heroImage {
          title
          fluid(maxWidth: 1800) {
            ...GatsbyContentfulFluid_withWebp_noBase64
          }
          ogimg: resize(width: 1800) {
            src
          }
        }
        body {
          childMarkdownRemark {
            timeToRead
            html
+           htmlAst
            excerpt(pruneLength: 320)
          }
        }
      }
    }
  `

6. Markdownにコンポーネントを書く

<custom-component></custom-component>

7. ビルドする

ビルドします!

おわりに

やってて気づいたんですが、文字列はpropsで渡せるのですが、画像を渡した際にgatsby-image等に噛ませられないなと、思いました

理想は画像も噛ませたいのですが、それには別の方法を考える必要がありそうです
続報をお待ち下さい

それでは!