GatsbyJS で React Helmet を使用してサイトの meta タグを設定する


こんにちは、Gaji-Labo アシスタントエンジニアの石垣です。

今回は React 用静的サイトジェネレーターの GatsbyJS で React Helmet を使用して、GatsbyJS サイト上の meta タグを設定する方法についてまとめたいと思います。

目的

GatsbyJS で作成されたサイトには、デフォルトでは meta タグや title 要素が設定されていません。

GatsbyJS で meta タグを設定するには、 gatsby-plugin-react-helmet プラグインを導入し、 React Helmet という head 要素を変更できる React コンポーネントを使用して設定します。

詳しい説明は gatsby-plugin-react-helmet の公式ドキュメントもご参照ください。

導入

まずは gatsby-plugin-react-helmet プラグインを導入します。

$ yarn add gatsby-plugin-react-helmet react-helmet

導入すると、以下のように GatsbyJS のページ上で React Helmet に meta タグや title 要素を記述して設定できるようになります。

import React from 'react';
import { Helmet } from 'react-helmet';

const ExamplePage = () => {
  return (
    <>
      <Helmet
        title="page title"
        link={[{ rel: 'canonical', href: 'canonical' }]}
        meta={[
          { name: 'description', content: 'description' },
          { property: 'og:description', content: 'og:description' },
          ...
        ]}
      />
      <div>page content</div>
    </>
  );
};

export default ExamplePage;

Helmet で囲んだ中で HTML タグのように記述することも可能です。

...
<Helmet>
  <title>page title</title>
  <link rel="canonical" href="canonical" />
  <meta name="description" content="description" />
  <meta name="og:description" content="og:description" />
  ...
</Helmet>
...

export default ExamplePage;

このように設定すると、ビルドした際には以下のような静的 HTML にビルドされます。

<head>
...
  <title data-react-helmet="true">page title</title>
  <link data-react-helmet="true" rel="canonical" href="canonical" />
  <meta data-react-helmet="true" name="description" content="description" />
  <meta data-react-helmet="true" property="og:description" content="og:description" />
  ...
</head>

外部コンポーネント化

実際に使用する際はページごとに React Helmet を置いて設定することはせず、外部コンポーネント化し、それに meta タグの props を渡して設定することになるかと思います。

以下のような Layout コンポーネントを用意して指定するようにします。

import React from 'react';
import { Helmet } from 'react-helmet';
import { StaticQuery, graphql } from 'gatsby';
import ogpImage from '../../static/images/ogp.png';

// ページの URL, title, description, type, og:image を渡せるように作成
const Layout = ({ children, pageUrl, ogpTitle, ogpDescription, ogpType, ogpThumbnail }) => (
  // StaticQuery を使用してコンポーネントに GraphQL で取得したデータを流し込む
  <StaticQuery
    query={graphql`
      query SiteMetaQuery {
        site {
          siteMetadata { // gatsby-config.js で設定した siteMetadata
            title
            description
            siteUrl
            name
          }
        }
      }
    `}
    render={data => {
      return (
        <>
          <Helmet
            title={ogpTitle || title}
            link={[{ rel: "canonical", href: pageUrl }]}
            meta={[
              { name: 'viewport', content: 'width=device-width, initial-scale=1, shrink-to-fit=no, viewport-fit=cover' },
              { name: 'description', content: ogpDescription || description },
              { name: 'twitter:card', content: 'summary' },
              { name: 'twitter:description', content: ogpDescription || description },
              { name: 'twitter:image', content: ogpThumbnail ? `${siteUrl}${ogpThumbnail}` : `${siteUrl}${ogpImage}` },
              { name: 'twitter:site', content: '@gaji_labo' },
              { name: 'twitter:text:title', content: ogpTitle || title },
              { property: 'og:description', content: ogpDescription || description },
              { property: 'og:image', content: ogpThumbnail ? `${siteUrl}${ogpThumbnail}` : `${siteUrl}${ogpImage}` },
              { property: 'og:site_name', content: name },
              { property: 'og:title', content: ogpTitle || title },
              { property: 'og:type', content: ogpType || 'website' },
              { property: 'og:url', content: pageUrl || siteUrl },
            ]}
          />
          <div>
            {children}
          </div>
        </>
      )
...

作成したコンポーネントは、ページ上で以下のように使用します。

import React from 'react';
import Layout from '../../components/common/Layout';

const ExamplePage = () => {
  return (
    <Layout
      pageUrl="page URL"
      ogpDescription="description"
      ogpTitle="page title"
    >
      page content
    </Layout>
  )
...

これでページごとに任意のデータを渡して meta タグや title 要素を設定することができるようになりました。

サイト上に置いた Markdown ファイルの Frontmatter から meta タグを取得したい時は、同様に GraphQL でデータを取得し、 Layout コンポーネントに渡すようにします。

import React from "react";
import { graphql } from "gatsby";
import Layout from "../components/common/Layout";

const ExamplePage = (props) => {
  const { data } = props;
  const { markdownRemark: post, site } = data;
  return (
    <Layout
      pageUrl={`${site.siteMetadata.siteUrl}${post.fields.slug}`}
      ogpTitle={post.frontmatter.title}
      ogpDescription={post.frontmatter.description || post.excerpt}
      ogpThumbnail={post.frontmatter.ogpThumbnail}
      ogpType="article"
    >
      <div dangerouslySetInnerHTML={{ __html: post.html }} />
    </Layout>
  );
};

export const pageQuery = graphql`
  query ContentByID($id: String!) {
    site {
      siteMetadata {
        siteUrl
      }
    }
    markdownRemark(id: { eq: $id }) {
      html
      excerpt(pruneLength: 300, truncate: true)
      fields {
        slug
      }
      frontmatter {
        title
        description
        ogpThumbnail
      }
    }
  }
`;
...

まとめ

今回は gatsby-plugin-react-helmet プラグインを使用して、GatsbyJS サイト上の meta タグを設定する方法についてまとめました。

GatsbyJS を使用している方の参考にしていただけたらと思います。

Gaji-Laboでは、JavaScriptフレームワーク経験が豊富なパートナーさんを募集しています

Gaji-Laboでは、開発チームの一員としてプロジェクトに一緒に取り組んでくれる業務委託のパートナーさんを募集しています。

現在は特にJavaScriptフレームワーク実践と業務経験が豊富なWebフロントエンドエンジニアを必要としています。React + TypeScript、Vue.js、Next.js、Nuxt.js など、あなたの得意なフレームワークを教えて下さい!

パートナー契約へのお問い合わせもお仕事へのお問い合わせも、どちらもいつでも大歓迎です。まずはオンラインでのリモート面談からはじめましょう。ぜひお気軽にお問い合わせください!

お問い合わせしてみる!

投稿者 Ishigaki Shotaro

未経験から Gaji-Labo に入社。現在は React/TypeScript/Next.js の案件で MUI を使ったコンポーネント組み込みを担当。プロジェクトチームのリードとして共に組み込み作業をしているメンバーの進行管理も行っています。休日はだいたい家で音楽を聴いており、たまにライブに出かけています。