サイトロゴ

ベル15の開発ブログ

非推奨になるreact-helmetからGatsby Head APIに書き換える方法

2022年09月08日 14:00

導入

先日、Gatsby.jsのバージョンを上げたところ、以下のような警告が出るようになりました。

warn gatsby-plugin-react-helmet: Gatsby now has built-in support for modyfing the document head. Learn more at https://gatsby.dev/gatsby-head

まだ警告の段階なので問題はありませんが、非推奨になる予定なのでやがて使えなくなる可能性があります。
react-helmet自体も2年以上更新されていないため、今後依存関係で問題が生じる可能性があります。



そこで、今回はreact-helmetから、その代わりに公式が出したAPIであるGatsby Head APIに書き換える方法を紹介します。
この記事の前提として、私はgatsby-starter-blogというテンプレートを使っています。
ですが、それ以外のテンプレートを使っているGatsby.jsユーザーの方にも役立つと思うので、ぜひ記事を読んでいただけると嬉しいです。


Gatsby Head APIとは

Gatsby Head APIとは、Gatsby 4.19.0から追加されたreact-helmetに代わる<head>タグに情報を追加できるAPIです。
Gatsby自体に組み込まれているため、バージョンが4.19.0以降であれば特にプラグインを追加することなく利用できます。


利用方法についてもそこまで難しくなく、react-helmetと比べて以下の利点があります。

  • バンドルサイズの低下
  • パフォーマンス向上
  • ページごとに動的に<head>タグを書き換え可能

なので、Gatsbyをこれからも使っていくのであれば、ぜひ利用することをお勧めします。

Gatsby Head APIの使い方

Gatsby Head APIの使い方を、react-helmetと比較しながら説明します。

事前準備

react-helmetからGatsby Head APIに書き換えるには事前準備が必要です。
具体的には、以下の2つの手順が必要です。

  • react-helmetのアンインストール
  • gatsby-config.jsからプラグインを削除

この手順をしないと、似た機能を持つ2つが競合して、意図しない動作になります。

react-helmetのアンインストール

まず、ターミナルで以下のコマンドを入力し、 react-helmet と gatsby-plugin-react-helmet の2つのパッケージをアンインストールします。


npmの場合

npm uninstall react-helmet gatsby-plugin-react-helmet

yarnの場合

yarn remove react-helmet gatsby-plugin-react-helmet

gatsby-config.jsからプラグインを削除

次に、gatsby-config.jsのpluginsにあるgatsby-plugin-react-helmetを削除します。
これで事前準備は完了です。

module.exports = {
// 途中省略
plugins: [
// 途中省略
- `gatsby-plugin-react-helmet`, //この行を削除
// 途中省略
]
}

基本的な使い方

それでは、Gatsby Head APIの基本的な使い方について紹介します。
react-helmetでは<Helmet>タグを書き、その中に<head>タグに追加するHTMLを書いていました。

import * as React from "react"
import { Helmet } from "react-helmet"
const Example = () => {
return (
// この部分
<Helmet>
<title>Gatsby Head API</title>
<meta name="description" content="Gatsby Head API Example" />
</Helmet>
<div>Example</div>
)
}
export default Example

Gatsby Head APIでは代わりに各ページにHeadという関数を定義し、その中に<head>タグに追加するHTMLを書きます。
具体的には、以下のような形です。

import * as React from "react"
const Example = () => {
return (
<div>Example</div>
)
}
export default Example
// この部分
export const Head = () => {
<>
<title>Gatsby Head API</title>
<meta name="description" content="Gatsby Head API Example" />
</>
}

このように、<head>タグに追加したいページにHead関数を定義し、その中にjsx記法で追加したいタグを書きます。
jsx記法なので、追加したいタグが2つ以上ある場合は、<></>(React Fragment)で囲う必要があります。


書き換えの具体的な手順

次に、<head>の部分をコンポーネント化している場合の書き換え方法を紹介します。
今回は、gatsby-starter-blogにあるSeoコンポーネントを例にとって説明します。
他のコンポーネントの場合は、自分のコンポーネントに置き換えて見てもらえると嬉しいです。


gatsby-starter-blogのSeoコンポーネントは、以下の実装になっています。

import { Helmet } from "react-helmet"
const Seo = ({ description, lang, meta, title, ogpImgPath }) => {
// 途中省略
return (
<Helmet
htmlAttributes={{
lang,
}}
title={title}
titleTemplate={titleTemplate}
meta={[
{
name: `description`,
content: metaDescription,
},
{
property: `og:title`,
content: title,
},
{
property: `og:description`,
content: metaDescription,
},
{
property: `og:type`,
content: type,
},
{
property: `og:site_name`,
content: defaultTitle,
},
{
property: `og:image`,
content: `${site.siteMetadata?.siteUrl}${imgPath}`,
},
{
name: `twitter:card`,
content: `summary_large_image`,
},
{
name: `twitter:creator`,
content: site.siteMetadata?.social?.twitter || ``,
},
{
name: `twitter:title`,
content: title,
},
{
name: `twitter:description`,
content: metaDescription,
},
].concat(meta)}
link={[
{
rel: `preconnect`,
href: `https://fonts.googleapis.com`,
},
{
rel: `preconnect`,
href: `https://fonts.gstatic.com/`,
crossorigin: "",
},
{
rel: `stylesheet`,
href: `https://fonts.googleapis.com/css?family=Noto+Sans+JP:wght@400;700&display=swap`,
},
]}
/>
)
}

これは、以下の書き方と同じ意味です。

import { Helmet } from "react-helmet"
const Seo = ({ description, lang, meta, title, ogpImgPath }) => {
// 途中省略
return (
<Helmet>
<html lang={lang} />
<title>{titleTemplate}</title>
<meta name="description" content={metaDescription} />
<meta property="og:title" content={title} />
<meta property="og:description" content={metaDescription} />
<meta property="og:type" content={type} />
<meta property="og:site_name" content={defaultTitle} />
<meta property="og:image" content={`${site.siteMetadata?.siteUrl}${imgPath}`} />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:creator" content={site.siteMetadata?.social?.twitter || ``} />
<meta name="twitter:title" content={title} />
<meta name="twitter:description" content={metaDescription} />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Noto+Sans+JP:wght@400;700&display=swap" />
</Helmet>
)
}

Gatsby Head APIに書き換えるうえで、後者の書き方のほうがわかりやすいので、今回は後者の書き方と比較し、書き換えていきます。


書き換えに必要なステップは以下の3つです。

  1. Seoコンポーネントの書き換え
  2. lang属性の書き換え
  3. 各ページの書き換え

それでは順に紹介していきます。

Seoコンポーネントの書き換え

Seoコンポーネントの書き換えは簡単です。
基本的には、<Helmet>タグを<>(React Fragment)に書き換え、react-helmetのインポート部分を削除するだけです。


ただし、1つ注意点があります。
Gatsby Head APIでは、<head>タグ内の書き換えしかできないため、それ以外の書き換え部分は取り除かなければいけません


先ほどの例ですと、<html lang={lang} />がそれに当たります。
なので、この部分と関連する部分を取り除きます。

// react-helmetのimport部分を削除
const Seo = ({ description, /*langを削除*/ meta, title, ogpImgPath }) => {
// 途中省略
return (
<>
{/*langを削除*/}
<title>{titleTemplate}</title>
<meta name="description" content={metaDescription} />
<meta property="og:title" content={title} />
<meta property="og:description" content={metaDescription} />
<meta property="og:type" content={type} />
<meta property="og:site_name" content={defaultTitle} />
<meta property="og:image" content={`${site.siteMetadata?.siteUrl}${imgPath}`} />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:creator" content={site.siteMetadata?.social?.twitter || ``} />
<meta name="twitter:title" content={title} />
<meta name="twitter:description" content={metaDescription} />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Noto+Sans+JP:wght@400;700&display=swap" />
</>
)
}
Seo.defaultProps = {
- lang: `ja`, //この行を削除
meta: [],
description: ``,
ogpImgPath: null,
}
Seo.propTypes = {
description: PropTypes.string,
- lang: PropTypes.string, //この行を削除
meta: PropTypes.arrayOf(PropTypes.object),
title: PropTypes.string.isRequired,
ogpImgPath: PropTypes.string,
}

追加で、各ページごとに<head>タグに追加できるようにしたい場合は、childrenという変数を使い、最後に追加します。
これにより、Seoコンポーネント内にタグを入れることで、そのページのみにタグを追加することができます。
これでこのステップは完成です。

const Seo = ({ description, meta, title, ogpImgPath, children /*追加*/ }) => {
// 途中省略
return (
<>
<title>{titleTemplate}</title>
<meta name="description" content={metaDescription} />
<meta property="og:title" content={title} />
<meta property="og:description" content={metaDescription} />
<meta property="og:type" content={type} />
<meta property="og:site_name" content={defaultTitle} />
<meta property="og:image" content={`${site.siteMetadata?.siteUrl}${imgPath}`} />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:creator" content={site.siteMetadata?.social?.twitter || ``} />
<meta name="twitter:title" content={title} />
<meta name="twitter:description" content={metaDescription} />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Noto+Sans+JP:wght@400;700&display=swap" />
+ {children}
</>
)
}

lang属性の書き換え

次に、lang属性の部分の実装を書き換えます。


先ほど説明したように、Gatsby Head APIでは、<head>タグ内のタグ以外は入れることができないため、代わりにgatsby-ssr.jsに以下の記載を追加します。
gatsby-ssr.jsがまだ存在していない場合は、gatsby-config.jsと同じ階層に新たにファイルを作成してください。

exports.onRenderBody = ({ setHtmlAttributes }) => {
setHtmlAttributes({ lang: "ja" })
}

これで、HTMLのlang属性をjaに設定することができました。

各ページの書き換え

最後に、各ページの記述を書き換えます。
具体的には、各ページのコンポーネント部分に書かれているSeoコンポーネントの部分を、新しく作ったHead関数内に移動するだけです。


具体的には、以下のように変更します。
Seoコンポーネントで受け渡すpropsの値が固定の場合と動的に変わる場合で実装が変わります。

propsの値が固定の場合

Seoコンポーネントでpropsが固定の場合は、SeoコンポーネントをHead関数内にそのまま移動するだけです。


変更前

const NotFoundPage = ({ data, location }) => {
const siteTitle = data.site.siteMetadata.title
return (
<Layout location={location} title={siteTitle}>
<Seo title="404: Not Found" />
<h1>404</h1>
<p>ページが見つかりません。</p>
</Layout>
)
}
export default NotFoundPage

変更後

const NotFoundPage = ({ data, location }) => {
const siteTitle = data.site.siteMetadata.title
return (
<Layout location={location} title={siteTitle}>
{/*Seoコンポーネントを削除*/}
<h1>404</h1>
<p>ページが見つかりません。</p>
</Layout>
)
}
export default NotFoundPage
+ export const Head = () => (
+ <Seo title="404: Not Found" />
+ )

propsが動的に変わる場合

Seoコンポーネントでpropsの値が動的に変わる場合は、Head関数で以下の値が受け取れるため、その値を利用します。

  • location
  • params
  • data
  • pageContext

これは、以下のように受け取れます。

export const Head = ({ location, params, data, pageContext }) => (
<>
<title>{pageContext.title}</title>
<meta name="description" content={data.page.description} />
</>
)

例えば、gatsby-starter-blogのblog-post.jsの場合、以下のように修正できます。


変更前

const BlogPostTemplate = ({ data, location }) => {
const post = data.markdownRemark
//途中省略
return (
<Layout location={location} title={siteTitle}>
<Seo
title={post.frontmatter.title}
description={post.frontmatter.description || post.excerpt}
ogpImgPath={post.frontmatter.ogpImgPath}
/>
{/*途中省略*/}
</Layout>
)
}

変更後

const BlogPostTemplate = ({ data, location }) => {
const post = data.markdownRemark
//途中省略
return (
<Layout location={location} title={siteTitle}>
{/*Seo部分の削除*/}
{/*途中省略*/}
</Layout>
)
}
+ export const Head = ({ data }) => (
+ <Seo
+ title={data.markdownRemark.frontmatter.title}
+ description={data.markdownRemark.frontmatter.description || data.markdownRemark.excerpt}
+ ogpImgPath={data.markdownRemark.frontmatter.ogpImgPath}
+ />
+ )

これで、Gatsby Head APIへの書き換えが完了です。


まとめ

今回は、react-helmetからGatsby Head APIに書き換える方法を紹介しました。


いくつか手順はあるものの、手順に沿って行けば、書き換えることができたと思います。
一度移行することで、今後エラーや警告なくブログ開発できると思うので、この記事を参考にしていただけたら幸いです。

参考記事