Gatsby.jsの画像最適化プラグインgatsby-imageを触ってみてわかったこと。

Gatsby.jsの画像最適化プラグインgatsby-imageを触ってみてわかったこと。:


はじめに

https://takumon.com/2018/10/21/#gatsby-image
@Takumon さんのwebページの記事を参考いたしました。gatsby.jsのプラグインがとても簡潔にまとめてあり勉強になりました。感謝を申し上げます。

今回は、gatsby.jsにおける画像の最適化を行ってくれるプラグインgatsby-imageについて、「実装したこと」「やりたかったこと」「できなかったこと」をまとめた記事です。


開発環境


◯ 基本環境


◯ プラグイン等

  • gatsby-image
  • gatsby-plugin-sharp
  • gatsby-transformer-sharp
  • gatsby-source-filesystem


gatsby-imageについて


公式サイトを読む


原文ママ

  • Loads the optimal size of image for each device size and screen resolution
  • Holds the image position while loading so your page doesn’t jump around as images load
  • Uses the “blur-up” effect i.e. it loads a tiny version of the image to show while the full image is loading
  • Alternatively provides a “traced placeholder” SVG of the image.
  • Lazy loads images which reduces bandwidth and speeds the initial load time
  • Uses WebP images if browser supports the format


日本語訳

  • 各デバイスのサイズと画面解像度に最適なイメージサイズを読み込みます
  • 画像の読み込み中に画像の位置を保持します
  • 画像全体が読み込まれている間に表示する画像の小さな画像を読み込みます。
  • レイジーは画像をロードして帯域幅を減らし、初期ロード時間を短縮します
  • ブラウザーがその形式をサポートしている場合、WebPイメージを使用します。


※超意訳※


画像最適化周りの面倒臭いことは、プラグインが全部いい感じにやってくれます


実装部分

gatsby-config.js
module.exports = { 
    plugins: {    
        { 
        resolve: `gatsby-source-filesystem`, 
            options: { 
                name: `images`, 
                path: `${__dirname}/src/images`, 
            }, 
        }, 
        `gatsby-transformer-sharp`, 
        `gatsby-plugin-sharp`, 
 
        ...(以下省略) 
    } 
} 
gatsby-config.jsでは、画像を入れておくディレクトリまでのパスを指定している。gatsby-imageはプラグインではなく、gatsby-transformer-sharpとgatsby-plugin-sharpに依存したライブラリなので、plugins:{}には記述する必要はない。

index.jsx
import React from 'react' 
import { Link, StaticQuery, graphql } from 'gatsby' 
import Img from 'gatsby-image' 
 
import Layout from '../components/layout'  // 詳細は割愛 
 
const IndexPage = () => ( 
    <StaticQuery 
        query={query} 
        render={ data => ( 
            <Layout> 
                <div> 
                    <Img fixed={data.file.childImageSharp.fixed}/> 
                </div> 
                <Link to="/page-2/">Go to page 2</Link> 
            </Layout> 
        )} 
    /> 
) 
 
export default IndexPage 
 
const query = graphql` 
    query { 
        file(relativePath: {eq: "logo.jpg"}) { 
            childImageSharp{ 
                fixed(width: 200) { 
                    ...GatsbyImageSharpFixed 
                } 
            } 
        } 
    } 
` 
これが最初の実装。GraphQLでローカルファイル検索を行って、検索に合致した画像を表示するといった一連の手順をシンプルに実装している。


やりたかったこと

  1. 複数画像の表示
  2. 様々な記述方法で対応
  3. パス指定のみで表示できるようにしたい


1. 複数画像の表示

const query = graphql` 
    query { 
        file(relativePath: {eq: "logo.jpg"}) { 
            childImageSharp{ 
                fixed(width: 200) { 
                    ...GatsbyImageSharpFixed 
                } 
            } 
        } 
    } 
` 
ここの部分において、画像を1つしか指定できていないことがわかる。

「1ページあたり1枚しか画像を使えないの…」みたいな疑問にぶち当たったのでGatsby.jsの公式レファレンスを読んでみた。
https://www.gatsbyjs.org/docs/graphql-reference/#aliasing

公式サイトのレファンレンスに書いてあるAliasingを用いれば、一度に複数のファイルを要求することができそう。と言うことで実装。

index.jsx
import React from 'react' 
import { Link, StaticQuery, graphql } from 'gatsby' 
import Img from 'gatsby-image' 
 
import Layout from '../components/layout' // 詳細は割愛 
 
 
const IndexPage = () => ( 
    <StaticQuery 
        query={query} 
        render={ data => ( 
            <Layout> 
                <div> 
                    <Img fixed={data.logo1.childImageSharp.fixed}/> 
                    <Img fixed={data.logo2.childImageSharp.fixed}/> 
                </div> 
                <Link to="/page-2/">Go to page 2</Link> 
            </Layout> 
        )} 
    /> 
) 
 
export default IndexPage 
 
const query = graphql` 
    query { 
        logo1:file(relativePath: {eq: "logo.jpg"}) { 
            childImageSharp{ 
                fixed(width: 200) { 
                    ...GatsbyImageSharpFixed 
                } 
            } 
        }, 
        logo2:file(relativePath: {eq: "logo2.jpg"}) { 
            childImageSharp{ 
                fixed(width: 200) { 
                    ...GatsbyImageSharpFixed 
                } 
            } 
        } 
    } 
` 


gazo.png


無事に表示できた。(今回は名前を変えただけで同じ画像を使ってる)

aliasingでは自由に名前を指定できるみたい。今回はlogo1とlogo2と言う名前を使ったけど、わかりやすい自分なりの名前をつけるとミスが起こらなくて済みそう。


2. 様々な記述方法で対応

const IndexPage = () => ( 
    <StaticQuery 
        query={query} 
        render={ data => ( 
            <Layout> 
                <div> 
                    <Img fixed={data.logo1.childImageSharp.fixed}/> 
                    <Img fixed={data.logo2.childImageSharp.fixed}/> 
                </div> 
                <Link to="/page-2/">Go to page 2</Link> 
            </Layout> 
        )} 
    /> 
) 
ここに書いてあるようにStaticQueryを使って描画しているが、もう少し直感的に書きたい気持ちがある。ってことで別の記述方法で実装してみる。

index.jsx
import React from 'react' 
import { Link, graphql } from 'gatsby' 
import Img from 'gatsby-image' 
 
import Layout from '../components/layout' 
 
export default props => { 
        return <Layout> 
                <div> 
                    <Img fixed={props.data.logo1.childImageSharp.fixed}/> 
                    <Img fixed={props.data.logo2.childImageSharp.fixed}/> 
                </div> 
                <Link to="/page-2/">Go to page 2</Link> 
            </Layout> 
} 
 
export const query = graphql` 
    query { 
        logo1:file(relativePath: {eq: "logo.jpg"}) { 
            childImageSharp{ 
                fixed(width: 200) { 
                    ...GatsbyImageSharpFixed 
                } 
            } 
        }, 
        logo2:file(relativePath: {eq: "logo2.jpg"}) { 
            childImageSharp{ 
                fixed(width: 200) { 
                    ...GatsbyImageSharpFixed 
                } 
            } 
        } 
    } 
` 


gazo.png


よしよし、表示できている。

Gatsby.jsではStaticQueryを使わない場合は、propsの中に自動的に格納される。fixedの中身が少し変わっているので注意したい。全体的なコード量も少なくなっているのでいい感じ。


3. パス指定のみで表示できるようにしたい

これが最後の挑戦。「GraphQLのクエリをいちいち書いているのなんてめんどくせぇ! 俺はパス指定だけで最適化したいんじゃ!」となったので挑戦。


…が、できなかった…

※ここから少し長いです※

端的に言うとjavascriptのテンプレートリテラル周りでうまくいかなかった。

やりたかったこと↓

Img.jsx
import * as React from 'react' 
import {graphql, StaticQuery} from 'gatsby' 
import Image from  'gatsby-image' 
 
const getQuery = path => { 
    return graphql` 
    query { 
        file(relativePath: {eq: "${path}"}) { 
            childImageSharp{ 
                fixed(width: 200) { 
                    ...GatsbyImageSharpFixed 
                } 
            } 
        } 
    } 
` 
} 
 
export default () => { 
    return <StaticQuery 
        query={ getQuery("logo.jpg") } 
        render={data => ( 
            <Image fixed={data.file.childImageSharp.fixed}/> 
        )} 
    /> 
} 
パスを指定するだけで動的にGraphQLクエリを生成し、ローカルにある画像の問い合わせを行う。しかしながら、これには弱点がある。
graphqlの引数はTemplateStringsArrayという型であり、これは `` (テンプレートリテラル)を使った文字列のことを指しています。そしてこれには大きな落とし穴があって、

const getQuery = path => { 
    return graphql` 
    query { 
        file(relativePath: {eq: "${path}"}) { 
            childImageSharp{ 
                fixed(width: 200) { 
                    ...GatsbyImageSharpFixed 
                } 
            } 
        } 
    } 
` 
} 
テンプレートリテラル内で式展開を行う場合、返ってくるのはstring型に変換されたものになってしまうのです。したがって、関数graphqlの引数の型が一致せずエラーになってしまう…

解決方法を探しに探したのですが、TemplateStringsArray型を引数に格納しようとあがいてもstring型に変換されてしまうのでどうしようもできず…

結局は諦めることにしました。(←技術力不足)


まとめ

色々ありましたが、gatsby-imageは面倒臭い画像最適化処理を全部やってくれる最高なライプラリです。この記事がgatsby.jsを使う際の参考になればと思います。

ここまで読んでくださり、ありがとうございました!

コメント

このブログの人気の投稿

投稿時間:2021-06-17 05:05:34 RSSフィード2021-06-17 05:00 分まとめ(1274件)

投稿時間:2021-06-20 02:06:12 RSSフィード2021-06-20 02:00 分まとめ(3871件)

投稿時間:2020-12-01 09:41:49 RSSフィード2020-12-01 09:00 分まとめ(69件)