tech.sinayaka.com

GatsbyJSのスターターの編集

2024-02-08
2025-07-13
7分
1344語
GatsbyJS Gatsby

スターターから始めたGatsbyJSがいうことを聞いてくれない!やりたいことができない! そう悩んでいた時期が私にもありました・・・ しかしながら、ぶつかり稽古を繰り返すうちに少しずつではありますが、理解は進むものです。

悩みはだいたい見た目に関すること

「タグのstyleをチョットいじりたいだけなんだけどなあ」 そう思っているだけでは進まないので、いろいろ調べてやっとわかったことを挙げていきます。

素直にREADME

製品を買ったら必ず説明書から読む人は存在しないと思いますが、説明書はマジで大切です。 インストールしたnode_modulesから、使用しているパッケージを探し、README.mdを見れば解決することも。

ある程度のアレンジを、製作者が事前に用意してくれています。 VSCodeの人は右クリックし「プレビューを開く」とすれば見やすいです。

シャドーイングでアレンジする

node_modulesから使用しているパッケージを探し、 自分のプロジェクトにコピーして編集することにより自分好みのページに変更することができます。

例えば、gatsby-theme-minimal-blogの記事のスタイルを変更したい場合、

node_modules
└── @lekoarts
    └── gatsby-theme-minimal-blog
        └── src
            └── components
                └── layout.tsx

をコピーし、自分のプロジェクトで

src
└── @lekoarts
    └── gatsby-theme-minimal-blog
        └── components

という構造のフォルダを作り、ファイルを貼り付けます。

ファイル内でimportされているファイルも再帰的にコピーしておく必要があります。

そして、記事内の変更したいタグにスタイルをつけていきます。

const Layout = ({ children, className = `` }: LayoutProps) => (
  <MDXProvider components={MdxComponents}>
    <Global
      styles={(t) => ({
        "*": {
          boxSizing: `inherit`,
        },
        "[hidden]": {
          display: `none`,
        },
        "::selection": {
          backgroundColor: get(t, `colors.text`),
          color: get(t, `colors.background`),
        },
        // ここにタグのスタイルを追加していく
        "hr": {
          marginTop: `2rem`,
          marginBottom: `2rem`,
        },
      })}
    />

クエリデータから変更する

componentsのファイルはクエリされたデータに対してどう表示するのかといった機能をつかさどると考えれば理解が早いです。

ではクエリデータから変更したい場合はどうすればいいのでしょうか?

useStaticQueryを使ってコンポーネントからクエリする

例えば、トップページや記事一覧にサムネイルが無いスターターの場合、 クエリから変更することで記事のFrontmatterからデータを引っ張って来れます。 今回扱ったgatsby-theme-minimal-blogでは「banner」という画像のフロントマターが coreのgatsby-node.jsで定義されていたのでクエリできました。

事前に画像データを扱うためのプラグインをインストールしておきます。

yarn add gatsby-plugin-image gatsby-plugin-sharp gatsby-transformer-sharp
  plugins: [
    `gatsby-plugin-image`,
    `gatsby-plugin-sharp`,
    `gatsby-transformer-sharp`,

gatsby-theme-minimal-blogの場合はhomepage.tsxが記事の一覧のクエリデータを受け取り、 listing.tsx→blog-list-item.tsxとデータを渡していました。 大元でデータをクエリし、それぞれのコンポーネントで画像データとして受け取るように変更します。

......
import { graphql, useStaticQuery } from "gatsby"
import { IGatsbyImageData } from "gatsby-plugin-image"

export type MBBlogProps = {
  posts: {
    slug: string
    title: string
    date: string
    excerpt: string
    description: string
    timeToRead?: number
    tags?: {
      name: string
      slug: string
    }[]
    // サムネイル用の項目を追加
    banner?: {
      childImageSharp?: {
        gatsbyImageData: IGatsbyImageData
      }
    }
  }[]
}
const Homepage = () => {
  const { tagsPath, basePath } = useMinimalBlogConfig()
  // useStaticQueryで記事のフロントマターからサムネイルデータ(banner)をクエリしたpostsを作成する
  const data = useStaticQuery<{
    allPost: {
      nodes: MBBlogProps[]
    }
  }>(graphql`
    query HomepageQuery {
      allPost(sort: { date: DESC }) {
        nodes {
          slug
          title
          date(formatString: "YYYY-MM-DD")
          excerpt
          description
          timeToRead
          tags {
            name
            slug
          }
          banner {
            childImageSharp {
              gatsbyImageData(width: 800, placeholder: BLURRED)
            }
          }
        }
      }
    }
  `)
  const posts = data.allPost.nodes
  return (
    <Layout>
      <Listing posts={posts} sx={{ mt: [4, 5] }} />
      <Flex sx={{ alignItems: `center`, justifyContent: `space-between`, flexFlow: `wrap` }}>
        <Link
          sx={(t) => ({ ...t.styles?.a, variant: `links.secondary`, marginY: 2 })}
          to={replaceSlashes(`/${basePath}/${tagsPath}`)}
        >
          View all tags
        </Link>
      </Flex>
    </Layout>
  )

そしてデータを受け取るコンポーネントでもサムネイル項目を増やし、

......
import { IGatsbyImageData } from "gatsby-plugin-image"

type ListingProps = {
  posts: {
    slug: string
    title: string
    date: string
    excerpt: string
    description: string
    timeToRead?: number
    tags?: {
      name: string
      slug: string
    }[]
    // サムネイル用の項目
    banner?: {
      childImageSharp?: {
        gatsbyImageData: IGatsbyImageData
      }
    }
  }[]
  className?: string
  showTags?: boolean
}

最終的な記事一覧の1要素を表示するコンポーネントでサムネイルを表示するようにします。

......
import { GatsbyImage, getImage, IGatsbyImageData } from "gatsby-plugin-image"

type BlogListItemProps = {
  post: {
    slug: string
    title: string
    date: string
    excerpt: string
    description: string
    timeToRead?: number
    tags?: {
      name: string
      slug: string
    }[]
    // ここでもサムネイル用の項目を追加
    banner?: {
      childImageSharp?: {
        gatsbyImageData: IGatsbyImageData
      }
    }
  }
  showTags?: boolean
}

const BlogListItem = ({ post, showTags = true }: BlogListItemProps) => {

  // 記事のフロントマターにbannerが指定されていればimageを作成し
  // Link内にサムネイルとして表示する
  const image = getImage(post.banner?.childImageSharp?.gatsbyImageData)
  
  return (
  <Box 
  sx={{
    borderRadius: `2xl`,
    boxShadow: `lg`,
    overflow: `hidden`,
    bg: `background`,
    p: 3,
    transition: `all 0.3s`,
    '&:hover': { boxShadow: `xl`, transform: `scale(1.01)` },
  }}>
    <Link to={post.slug} sx={(t) => ({ ...t.styles?.a, fontSize: [1, 2, 3], color: `text` })}>
      {image && (
        <GatsbyImage
          image={image}
          alt={post.title}
          sx={{ borderRadius: `lg`, mb: 3,
            height: `10rem`, // 高さを固定
            width: `100%`,  // 幅を100%にして親要素に合わせる
            objectFit: `cover`, // 画像がはみ出さないようにリサイズ
           }}
        />
      )}
      {post.title}
    </Link>

終わりに

シャドーイングする際、どこで何を扱っているのかを探し出すのが一番のネックです。

これを解決するには自分の経験と語彙力、それと「ぶつかり稽古」しかありません。

※追記:結局GatsbyJSは扱いづらく、ビルドも遅いのでastroに移行中・・・




Copyright 2025
サイトマップ