スターターから始めた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に移行中・・・