筋肉チョットデキル

Gatsbyで画像を取り扱う

2020年06月22日

Gatsby

Gatsby での基本的な画像の取り扱いについてメモ!

必要なプラグイン

gatsby-image
GatsbyのGraphQLクエリとシームレスに動作するように特別に設計されたReactコンポーネント。
サイトの画像読み込みを簡単かつ完全に最適化する。
画像処理ライブラリSharpの機能を提供する。
画像処理ライブラリSharpでサポートされている画像タイプからImageSharpノードを作成する。
ローカルファイルからFileノードを作成する。

GraphQL で取得する

ファイル名はprofile-pic.jpgであり fluid(伸縮)し最大幅は 400px, 対応ブラウザでは WebP 画像で表示して最適化する場合、このような GraphQL クエリを作成する。

GraphQLクエリ
query {
file(relativePath: { eq: "profile-pic.jpg" }) {
childImageSharp {
fluid(maxWidth: 400) {
base64
aspectRatio
src
srcSet
srcWebp
srcSetWebp
sizes
}
}
}
}
出力結果を見る

fragments を使う

先程は以下のフィールドを指定したが、毎回指定するのは大変でミスもありそうだ。共通化したい。。

  • base64
  • aspectRatio
  • src
  • srcSet
  • srcWebp
  • srcSetWebp
  • sizes

そこでfragmentsというものがあり簡略化して書ける!

GraphQLクエリ
query {
file(relativePath: { eq: "profile-pic.jpg" }) {
childImageSharp {
fluid(maxWidth: 400) {
...GatsbyImageSharpFluid_withWebp
}
}
}
}
出力結果を見る

gatsby-image の fragments はgatsby-transformer-sharp/src/fragments.jsで確認ができます!
このように fragments はプラグインで定義されていたり、自分で定義することも可能です。

gatsby-image で画像を表示する

たとえばsrc/pages/index.jsで表示する例を見てみましょう。

src/pages/index.js
import React from 'react';
import { graphql } from 'gatsby';
import Image from 'gatsby-image';
export default ({ data }) => <Image fluid={data.file.childImageSharp.fluid} />;
export const query = graphql`
query {
file(relativePath: { eq: "profile-pic.jpg" }) {
childImageSharp {
fluid(maxWidth: 400) {
...GatsbyImageSharpFluid_withWebp
}
}
}
}
`;

まず以下の部分で、GraphQL クエリをexportしています。
変数名queryはなんでも構いません。

export const query = graphql`
query {
file(relativePath: { eq: "profile-pic.jpg" }) {
childImageSharp {
fluid(maxWidth: 400) {
...GatsbyImageSharpFluid_withWebp
}
}
}
}
`;

exportしたクエリの結果は props で受け取ることができます。
クエリの出力結果は以下でdataというプロパティに値が入っているので分割代入で受け取っています。

GraphQL出力結果
{
"data": {
"file": {
"childImageSharp": {
"fluid": {
"base64": "data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAAMBAAAAAAAAAAAAAAAAAAIDBAX/xAAWAQEBAQAAAAAAAAAAAAAAAAABAgD/2gAMAwEAAhADEAAAAetCeAdrCxfxiiwS/wD/xAAcEAACAgIDAAAAAAAAAAAAAAABAgADERIEEyL/2gAIAQEAAQUCJAD+AMsGlr7q3K1lpPXaTmpQV//EABURAQEAAAAAAAAAAAAAAAAAABBB/9oACAEDAQE/ASn/xAAYEQACAwAAAAAAAAAAAAAAAAAAARARMf/aAAgBAgEBPwEoWR//xAAbEAADAAIDAAAAAAAAAAAAAAAAAREQMQISUf/aAAgBAQAGPwKMpfTVOrnFk3hY/8QAGxABAAMAAwEAAAAAAAAAAAAAAQARMSFRgUH/2gAIAQEAAT8h9URFuveYynBcWOHyLsnFgsJxNIJpLx2S9vc//9oADAMBAAIAAwAAABCj0D//xAAYEQADAQEAAAAAAAAAAAAAAAAAAREQMf/aAAgBAwEBPxBRdKPH/8QAGBEAAgMAAAAAAAAAAAAAAAAAATEAEBH/2gAIAQIBAT8QwlXy5//EAB0QAQEBAAICAwAAAAAAAAAAAAERACExQWFRcYH/2gAIAQEAAT8Q9Sgc6KQvBCL+YV4DsZFEAr0q+O9YxLboHUcFKQTgvrnKpH5NUGoW+c/FpHH0b//Z",
"aspectRatio": 1,
"src": "/static/0c1679c2f769226599c1b61833c382b9/2244e/profile-pic.jpg",
"srcSet": "/static/0c1679c2f769226599c1b61833c382b9/86e11/profile-pic.jpg 100w,\n/static/0c1679c2f769226599c1b61833c382b9/f836f/profile-pic.jpg 200w,\n/static/0c1679c2f769226599c1b61833c382b9/2244e/profile-pic.jpg 400w",
"srcWebp": "/static/0c1679c2f769226599c1b61833c382b9/1f5c5/profile-pic.webp",
"srcSetWebp": "/static/0c1679c2f769226599c1b61833c382b9/d1f52/profile-pic.webp 100w,\n/static/0c1679c2f769226599c1b61833c382b9/61e93/profile-pic.webp 200w,\n/static/0c1679c2f769226599c1b61833c382b9/1f5c5/profile-pic.webp 400w",
"sizes": "(max-width: 400px) 100vw, 400px"
}
}
}
}
}

そのなかのfluid。つまりこのようなオブジェクトを

fluid
{
"base64": "data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAAMBAAAAAAAAAAAAAAAAAAIDBAX/xAAWAQEBAQAAAAAAAAAAAAAAAAABAgD/2gAMAwEAAhADEAAAAetCeAdrCxfxiiwS/wD/xAAcEAACAgIDAAAAAAAAAAAAAAABAgADERIEEyL/2gAIAQEAAQUCJAD+AMsGlr7q3K1lpPXaTmpQV//EABURAQEAAAAAAAAAAAAAAAAAABBB/9oACAEDAQE/ASn/xAAYEQACAwAAAAAAAAAAAAAAAAAAARARMf/aAAgBAgEBPwEoWR//xAAbEAADAAIDAAAAAAAAAAAAAAAAAREQMQISUf/aAAgBAQAGPwKMpfTVOrnFk3hY/8QAGxABAAMAAwEAAAAAAAAAAAAAAQARMSFRgUH/2gAIAQEAAT8h9URFuveYynBcWOHyLsnFgsJxNIJpLx2S9vc//9oADAMBAAIAAwAAABCj0D//xAAYEQADAQEAAAAAAAAAAAAAAAAAAREQMf/aAAgBAwEBPxBRdKPH/8QAGBEAAgMAAAAAAAAAAAAAAAAAATEAEBH/2gAIAQIBAT8QwlXy5//EAB0QAQEBAAICAwAAAAAAAAAAAAERACExQWFRcYH/2gAIAQEAAT8Q9Sgc6KQvBCL+YV4DsZFEAr0q+O9YxLboHUcFKQTgvrnKpH5NUGoW+c/FpHH0b//Z",
"aspectRatio": 1,
"src": "/static/0c1679c2f769226599c1b61833c382b9/2244e/profile-pic.jpg",
"srcSet": "/static/0c1679c2f769226599c1b61833c382b9/86e11/profile-pic.jpg 100w,\n/static/0c1679c2f769226599c1b61833c382b9/f836f/profile-pic.jpg 200w,\n/static/0c1679c2f769226599c1b61833c382b9/2244e/profile-pic.jpg 400w",
"srcWebp": "/static/0c1679c2f769226599c1b61833c382b9/1f5c5/profile-pic.webp",
"srcSetWebp": "/static/0c1679c2f769226599c1b61833c382b9/d1f52/profile-pic.webp 100w,\n/static/0c1679c2f769226599c1b61833c382b9/61e93/profile-pic.webp 200w,\n/static/0c1679c2f769226599c1b61833c382b9/1f5c5/profile-pic.webp 400w",
"sizes": "(max-width: 400px) 100vw, 400px"
}

gatsby-imageからimportしたコンポーネントに渡すことで最適化した画像を表示します。

import Image from 'gatsby-image';
export default ({ data }) => <Image fluid={data.file.childImageSharp.fluid} />;

岡本 侑貴@筋肉チョットデキル

筋肉バカ。筋トレしてコード書いて、毎日幸せに生きてる。ボディビルにドハマリ。2021年東京オープンボディビル選手権で最高の身体に仕上げてつよつよエンジニアになる!!

Made with Gatsby& ChakraUi

Yuuki Okamoto • 2020