| 使用ソフトウェア | バージョン | 備考 | 
|---|---|---|
| Gatsby.js | 4.20 | APIは4.19から使用可能 | 
Gatsby.js v4.19よりgatsby-plugin-react-helmetが将来的に廃止される模様。
代わりに、公式でGatsby Head APIと呼ぶ機能が実装されたため、プラグインなしでheadタグ内にtitleやmetaといったタグを追加することが出来るようになっている。
gatsby-plugin-react-helmetのページに廃止予定(will be deprecated)と書かれているため、いずれ更新がとまると思われる。
いままでreact-helmetに依存することでhead内にタグを書き込んでいた人が多いと思う。
今回こちらを廃止して切り替えということは、わざわざAPIに書き換える作業コストが必要となる。
それに見合うメリットはあるのだろうか。
公式によると
というメリットがあるらしい。
特に最近はWebサイトの性能評価がどんどん厳しくなっているため(1)のパフォーマンス向上で有利かと個人的に考えている。
もちろん現状のgatsby-plugin-react-helmetはまだ正常動作するため、すぐさま切り替える必要はない。
実装前にgatsby-config.jsからgatsby-plugin-react-helmetをコメントアウト(可能ならアンインストール)する。
これを行わずAPIで実装するとエラーでビルドできない。
アンインストールのコマンド例を掲載しておく
npm uninstall gatsby-plugin-react-helmet react-helmet念のため上はアンインストールコマンドなので慎重に
Gatsby Head APIを使った新しい方法はコンポーネントには実装できない。
pagesかtemplateにだけ利用できる。
たとえばindexページはpagesに当たる(固定ページ)
その中からLayoutなどのコンポーネントを呼び出して使用するというのは基本である。
このときLayout内からheadタグに書き込むことはできないという意味。
この場合親になるindexからヘッダを書き込む。
つまりsrc > componentsに入っているjsからは使えないと覚えておいて良いだろう。
他にもgatsby-node.jsからcreatePages関数で生成されるページのテンプレートからAPIを呼ぶことが出来る。
したがってBLOG記事などビルド時に生成されるページでもこのAPIは使用できる。
Gatsby Head APIを使うにあたって特別なインポートは必要ない。
Headという関数をexportしてやりその中にtitleやmetaタグを書いておくだけで自動的に挿入される。
ただしGatsby.jsのバージョンが4.19以上である必要がある。
次が最も簡単な例。
import * as React from "react"
const headTest = () => {
    return (<div>test</div>)
}
export default headTest
//次が新しいコード。必ずHeadという名前の関数。
export const Head = () => {
    return (<title>ヘッダテスト</title>)
}このようにHeadという関数を別途exportしており、その中のreturnを使ってheadに記述したいタグを書いている。
少々理解しにくい人もいるかもしれないが、このHead()関数内でreturnしたタグがGatsby側で処理されてheadに注入されるという仕組みである。
言うまでもないかもしれないが通常headタグに書かないようなタグは使えない。
使えるのは次のタグ。
link, meta, style, title, base, script, noscript.
このままだとハードコードしたデータしか使えない気がするが、そんなことはない。
記事名からタイトルを変えたい、説明文を変えたいなどのケース。
Headを次のように書いて外部からのプロパティを読み込める。
export const Head = ({ location, params, data, pageContext }) => (
  <>
  略各プロパティを説明すると
location: location.pathnameとしてやることで現在のURLが取得できるparams: URLのパラメタを受け取る。matchPathという機能を使うときだそうだが使ったこと無いので不明data: GraphQLで記述したデータが入ってくる。つまりBLOG記事の内容やタイトル、日付、画像のアドレスなどはここから取る。pageContext: createPage関数で渡ってくるデータを受け取る。一番よくあるのはdataを使うことだと思う。
これはどこからくるのかというと、各ページにて
export const query = graphql`クエリ~~のように指定して取ってくるクエリのことを指している。
これを利用することでtemplateで様々なページが生成されたときにも個別のタイトルなどを付与することが可能。
またはuseStaticQueryを利用しても良さそうだ。
import * as React from "react"
import { graphql, useStaticQuery } from "gatsby"
const headTest = () => {
    return (<div>test</div>)
}
export default headTest
export const Head = () => {
    const metaData = useStaticQuery(graphql`
        query {
            site {
              siteMetadata {
                title
                description
              }
            }
          }
      `)
    return (
        <>
            <title>{metaData.site.siteMetadata.title}</title>
        </>
    )
}こちらは最小限しかテストしてないので動かないクエリもあるかもしれない。
上の方法だけだとページごとに別々のHead()関数として書いてやらないといけないような気がする。
実はコンポーネントの中にHead()が使えないだけでHead()の中身をコンポーネント化することは可能。
例えば次のようなページを書いて
import * as React from "react"
import Seo from '../components/seo-head' //ここでhead用コンポーネントを呼ぶ
const headTest = () => {
    return (<div>test</div>)
}
export default headTest
//Head()の中でコンポーネントを利用
export const Head = () => {
    return (
        <Seo
            title="ここにタイトル"
            twitter="Ultra-Noob"
        />
    )
}そしてSEOコンポーネント(ここではseo-head.js)の中身は
import React from "react"
const SEO = ({ title, twitter }) => {
    return (
        <>
            <title>{title}</title>
            <meta name="twitter:creator" content={twitter} />
        </>
    )
}
export default SEOブラウザで確認すると次のタグが正しく入っている。
このようにHead()関数内はコンポーネント化できるので再利用が可能。
各ページごとにHead()関数は毎回exportしてやる必要があるので注意。
その中身をコンポーネント化できますよという意味。
上で特定のタグしか使えないと書いたが、もちろんJSXなので条件分岐が可能。
私が使うケースだとnoindexのmetaタグを入れるかどうかを分ける場合。
上のSEOコンポーネントに書き加えて
const SEO = ({ title, twitter, isNoindex }) => {
    return (
        <>
            <title>{title}</title>
            <meta name="twitter:creator" content={twitter} />
            {
                isNoindex ? <meta name="robots" content="noindex" /> : null
            }
        </>
    )
}isNoindexにtrueを入れたときだけnoindexのメタタグが書かれるようになる。
公式よりこの他にもidを使うことでタグを分けられるかもしれない。
これに関しては同じタグを排除する機能なので違うかも?
テストしていないので公式を読んだ上で試してもらえたらと思う。
謎の技術研究部の本番サイトで実装前と実装後のLighthouseのスコアを計測した。
とは言ったものの殆ど差がでなかったのでスコアも掲載しない。
headタグの仕組みを改善した程度で大きくスコアが上がるということが無いというのは少し考えれば当たり前ではある。
とは言え、過去の私のテストから外部プラグインのインポートは少ないほうがスコアが上がるのでreact-helmetを読み込まないだけ有利になっていると予想できる。
少しでも効果があるのならば実装するに越したことはない。
公式のAPIページのみならず次のSEOコンポーネント解説ページが参考になる。
Adding an SEO Component | Gatsby(英文)
この記事でも多くの箇所で上を参照させていただいている。
より深く知りたい場合は読んでもらえたらと思う。
相変わらずGatsby.jsの記事に関しては解説が難しく理解してもらえてるかどうか怪しい。
ひとまず実装されたばかりで日本語の記事が見当たらなかったため率先して執筆させていただいた。
パフォーマンスと今後のアップデートを考慮して当サイトでは早速実装した。
