Contentfulで投稿した画像をGatsbyで最適化して出力してみる

2022.07.18

どうも、ベルリンオフィスの小西です。

現在、Gatsbyでの画像の取り扱いには Gatsby Image plugin( gatsby-plugin-image ) が便利です(旧公式プラグイン gatsby-image はすでに非推奨)。

Gatsby Image plugin は画像のレスポンシブ最適化、スタイリング、読み込み方法の指定("eager" ∣ "lazy”)などが可能で、これ一つで静的・ダイナミックどちらの画像の出力にも対応できます。また gatsby-image より画像の読み込み方法の簡素化、使い勝手の向上が図られています。

ヘッドレスCMSのContentfulから投稿された画像をGatsbyで取得&表示させる場合も、ただ <img> で出力するのではなく、最適化して表示することが可能です。

今回はContentful側での投稿パターンに応じて画像を最適化する方法を紹介します。

前提

  • Gatsby: Ver.4 以降
  • Gatsbyプラグイン gatsby-source-contentful : Ver.7以降

1. コンテンツモデルが Media として投稿された画像の場合

Contentful側

Contentfulのコンテンツモデル = Media は、画像を含むメディアアセットの投稿に利用できます。

例えば記事のサムネイル、商品イメージなど、記事中の本文とは独立したメディアの登録に最適です。

Contentfulダッシュボードでいうと下記が該当します。

contentful

Gatsby側コード

<GatsbyImage> コンポーネントを使います。

Gatsbyプラグイン gatsby-source-contentfulのGatsby Ver4に互換性のあるバージョンでは、Contentfulから取得した画像は gatsbyImageData オブジェクトを持つため、それをコンポーネントの必須image属性として渡します。

実際のページにサムネイルを表示するコードは下記のようになります。

src/pages/sample.js

import React from "react";
import { graphql } from "gatsby";
import { GatsbyImage } from "gatsby-plugin-image"

const SamplePage = ({ data }) => {
  const post = data.contentfulSamplePost;
  return (
  <>
    <h1>{post.title}</h1>

    <GatsbyImage
      image={post.thumbnail.gatsbyImageData}
      alt={post.thumbnail.title}
    />

  </>
  )
}

export default SamplePage

export const pageQuery = graphql`
  query {
    contentfulSamplePost( slug: {eq: "sample"} ) {
      title
      thumbnail {
        title
        gatsbyImageData
      }
    }
  }
`;

<GatsbyImage>で利用できるオプション

gatsbyImageData オブジェクトはGatsby Image pluginの仕様に沿うため、さまざまなオプションが利用可能です。

指定方法はGraphQL リゾルバにオプションを投げるだけです。

export const pageQuery = graphql`
  query {
    contentfulSamplePost( slug: {eq: "sample"} ) {
      thumbnail {
        gatsbyImageData(
          width: 600
          placeholder: BLURRED
          formats: [AUTO, WEBP, AVIF]
          quality: 10
        )
      }
    }
  }
`;

その他のオプションを詳しく知りたい方は → https://www.gatsbyjs.com/docs/reference/built-in-components/gatsby-plugin-image/#gatsbyimage

ただし、上記は便利ですが、記事の文中などに差し込まれる画像には適用されません。

記事中に埋め込まれた画像の最適化については次に説明します。

2. マークダウン記事中の画像の場合

Contentfulで長文を投稿する場合マークダウン形式が最も一般的です。記事中にメディアを埋め込むこともでき、それらは 通常の <img> タグとしてGatsbyに渡ってくるため、そのまま出力すると上で紹介したGatsbyImageのような最適化ができません。

そのため、例えばContentfulで非常に大きなサイズの画像が投稿されていた場合、Gatsbyアプリ側のwidthを超えて不要なサイズの画像が読み込まれてしまい、ユーザーフレンドリーではありません。

この問題を、公式プラグイン gatsby-remark-images-contentful を使って解決します。

Contentful側

今回利用するプラグインはMarkdown式の本文で動くため、Contentful側では [Long text] 形式の長文入力フィールドを使います。

contentful

contentful

Gatsby側設定&コード

必要なパッケージのインストール

npm install gatsby-remark-images-contentful

gatsby-config.js

module.exports = {
  ...(略)
  plugins: [
    `gatsby-plugin-image`,
    {
      resolve: `gatsby-transformer-remark`,
      options: {
        plugins: [
          {
            resolve: `gatsby-remark-images-contentful`,
            options: {
              maxWidth: 600,
              showCaptions: true,
            },
          },
        ],
      },
    },
    ...(略)
  ],
}

設定は以上です。

これだけでContentfulマークダウン内の画像に対して、遅延読み込みなどの最適化が実施されます。

オプションはフロントのテンプレート側ではなく、 gatsby-config.js で指定します。

gatsby-remark-images-contentfulで利用できるオプション

  • maxWidth … 画像の最大横幅を指定します(デフォルト: 650
  • linkImagesToOriginal … リサイズや最適化がされていないオリジナル画像へのリンクを自動で貼ります(デフォルト: true
  • showCaptions … 画像のタイトルを各画像のキャプションとして表示します(デフォルト: false
  • wrapperStyle … 画像をdivでラップするスタイリングを指定します(例: margin-bottom:10px; background: red;)
  • backgroundColor … イメージ背景色の指定(デフォルト: white
  • withWebp … WebPを追加で生成し srcset に追加します(デフォルト: false
  • loading lazy … 画像の読み込み方法( lazyeagerauto )を指定します(デフォルト: lazy

gatsby-remark-images-contentfulのインストールに問題が起こったら

gatsby-remark-images-contentful のインストール中でエラーが発生することがあります。

必須プラグインがない場合

There was a problem loading plugin "gatsby-transformer-remark". Perhaps you need to install its package?
Use --verbose to see actual error.

素直に親プラグインをインストールします。

npm install gatsby-transformer-remark

プラグインの互換性で怒られる場合

Something went wrong installing the "sharp" module

dlopen(/Users/misiek/dev/gatsby-starter-blog/node_modules/sharp/build/Release/sharp.node, 1): Library not loaded: @rpath/libglib-2.0.dylib
  Referenced from: /Users/misiek/dev/gatsby-starter-blog/node_modules/sharp/build/Release/sharp.node
  Reason: Incompatible library version: sharp.node requires version 6001.0.0 or later, but libglib-2.0.dylib provides version 5801.0.0

関連プラグインをアップデートしましょう。

npm install gatsby-plugin-sharp gatsby-plugin-manifest gatsby-remark-images-contentful gatsby-source-contentful gatsby-transformer-sharp gatsby-transformer-sqip


以上、Contentfulの画像をGatsbyで最適化する2パターンを紹介してみました。

クラスメソッドはContentfulのパートナーとして導入のお手伝いをさせていただいています。

ご興味のある方はお気軽にお問い合わせください。

参考