【AstroJS】 Markdown のフロントマターで設定した画像を最適化する

heroImage

1. はじめに

yarn create astro の blog テンプレートを使えば、すぐにブログサイトを構築することが出来ます。しかし、blog テンプレートで表示される一部の画像は、最適化処理がされていません。これは、<img> タグを用いて画像を表示しているのが原因です。AstroJS では、<Image /> コンポーネントを使用することで画像が最適化されます 1 。本記事では、AstroJS の blog テンプレート内で使用されている <img> タグを <Image /> コンポーネントに置換し、画像が最適化されるようにする手順について記述します。また、本記事は Node.js と Yarn がインストールされている前提で記述しています。

Terminal window
1
$ node -v
2
v20.11.0
3
$ yarn -v
4
1.22.21

2. テンプレート

まずは、yarn create astro で blog テンプレートを作成します。

Terminal window
1
$ yarn create astro
2
yarn create v1.22.21
3
[1/4] Resolving packages...
4
[2/4] Fetching packages...
5
[3/4] Linking dependencies...
6
[4/4] Building fresh packages...
7
8
success Installed "create-astro@4.7.2" with binaries:
9
- create-astro
10
[########################################] 40/40
11
astro Launch sequence initiated.
12
13
dir Where should we create your new project?
14
./flaky-field
15
16
tmpl How would you like to start your new project?
17
Use blog template
18
19
ts Do you plan to write TypeScript?
20
Yes
21
22
use How strict should TypeScript be?
23
Strict
24
25
deps Install dependencies?
26
Yes
27
28
git Initialize a new git repository?
29
No
30
Sounds good! You can always run git init manually.
31
32
Project initialized!
33
Template copied
34
TypeScript customized
35
Dependencies installed
36
37
next Liftoff confirmed. Explore your project!
38
39
Enter your project directory using cd ./flaky-field
40
Run yarn dev to start the dev server. CTRL+C to stop.
41
Add frameworks like react or tailwind using astro add.
42
43
Stuck? Join us at https://astro.build/chat
44
45
╭─────╮ Houston:
46
Good luck out there, astronaut! 🚀
47
╰─────╯

3. 編集作業

初期設定では、heroImage は文字列と定義されているので、これを画像に置換します。コンテンツコレクションについて詳しく知りたい方は AstroJS の公式ドキュメント 2 を参照ください。

src/content/config.ts
1
import { defineCollection, z } from 'astro:content'
2
3
const blog = defineCollection({
4
type: 'content',
5
// Type-check frontmatter using a schema
6
schema: ({ image }) =>
7
z.object({
8
title: z.string(),
9
description: z.string(),
10
// Transform string to Date object
11
pubDate: z.coerce.date(),
12
updatedDate: z.coerce.date().optional(),
13
heroImage: z.string().optional(),
14
heroImage: image(),
15
}),
16
})
17
18
export const collections = { blog }

次に、画像を表示している src/pages/blog/index.astrosrc/layouts/BlogPost.astro を編集します。それぞれ、<Image /> コンポーネントをインポートして、<img> タグを <Image /> コンポーネントに置換しています。

src/pages/blog/index.astro
1
---
2
import { Image } from 'astro:assets'
3
---
4
5
<img width={720} height={360} src={post.data.heroImage} alt="" />
6
<Image src={post.data.heroImage} alt={''} />
src/layouts/BlogPost.astro
1
---
2
import { Image } from 'astro:assets'
3
---
4
5
{heroImage && <img width={1020} height={510} src={heroImage} alt="" />}
6
<Image src={heroImage} alt={''} />

最後に、src/content/blog/*.mdheroImage で設定されている画像パスを編集します。

src/content/blog/*.md
1
---
2
heroImage: "/blog-placeholder-1.jpg"
3
heroImage: "/public/blog-placeholder-1.jpg"
4
5
heroImage: "/blog-placeholder-2.jpg"
6
heroImage: "/public/blog-placeholder-2.jpg"
7
8
heroImage: "/blog-placeholder-3.jpg"
9
heroImage: "/public/blog-placeholder-3.jpg"
10
11
heroImage: "/blog-placeholder-4.jpg"
12
heroImage: "/public/blog-placeholder-4.jpg"
13
14
heroImage: "/blog-placeholder-5.jpg"
15
heroImage: "/public/blog-placeholder-5.jpg"
16
---

これで作業は完了です。yarn run dev で起動し、http://localhost:4321/blog/ で表示されている画像のソースを表示させると、以下のように最適化されていると思います。

1
<img
2
src="/_image?href=%2F%40fs%2Froot%2Fwork%2Fwhole-wasp%2Fpublic%2Fblog-placeholder-1.jpg%3ForigWidth%3D960%26origHeight%3D480%26origFormat%3Djpg&amp;f=webp"
3
alt=""
4
data-astro-cid-5tznm7mj=""
5
width="960"
6
height="480"
7
loading="lazy"
8
decoding="async"
9
data-astro-source-file="/root/work/whole-wasp/node_modules/astro/components/Image.astro"
10
data-astro-source-loc="34:2"
11
/>

4. おわりに

ここまで、AstroJS の blog テンプレート内で使用されている <img> タグを <Image /> コンポーネントに置換し、画像が最適化されるようにする手順について記述してきました。AstroJS は、画像の扱いに少し癖 (Markdown 本文で画像を読み込む際に、絶対パスを設定すると最適化されないなど) がある印象です。GatsbyJS 3 のように GraphQL で統一するということも出来ないので、お作法を覚えるしかないですね。画像周りの知見が溜まったら記事にしたいと思います。


  1. Astro Docs, Images:https://docs.astro.build/en/guides/images/

  2. Astro Docs, Content Collections:https://docs.astro.build/en/guides/content-collections/

  3. トレードオフで Plugin 地獄と GraphQL 地獄に苦しめられる