AstroJS における画像ファイルの取り扱い説明書

heroImage

1. はじめに

AstroJS では、デフォルトで画像処理ライブラリの Sharp が組み込まれており、同じく AstroJS にデフォルトで組み込まれている <Image> コンポーネントを用いることで、画像を最適化してくれます。外部パッケージのインストールや設定なしで、最適化処理が行われるのはユーザーフレンドリーだと思います。その一方で、画像ファイルを読み込み際に、独特の お作法 が存在します。慣れないうちは、この お作法 のせいで頭を悩ませると思います。本記事では、AstroJS における画像ファイルの読み込み挙動について、可能な限り網羅的に解説したものになります。また、本記事は 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
./satellite-solstice
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 ./satellite-solstice
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
╰─────╯
48
Done in 46.94s.

3. Astro ファイル

3.1. <img> タグ

AstroJS で最もシンプルに画像を表示させる方法は、public フォルダに画像ファイルを配置して <img> タグで表示する方法です。以下の、どの記法でも画像が表示されます。AstroJS では、public フォルダに配置されたファイルはビルド時に、そのまま root にコピーされます。GatsbyJS や Hugo の static フォルダと同じ役割です。

src/pages/index.astro
1
---
2
3
---
4
5
<img src="Apple.jpg" />
6
<img src="/Apple.jpg" />
7
<img src="./Apple.jpg" />

他に、<img> タグを用いて画像ファイルを表示する方法を色々と検証してみました。結果としては、public フォルダに配置している画像ファイルを <img> タグで表示する場合は、上記の方法で表示するが良いと思います。また、src フォルダに配置している画像ファイルを <img> タグで表示する場合は、絶対パスを用いるのが良いと思います。

src/pages/index.astro
1
---
2
3
---
4
5
<!-- 絶対パス -->
6
<img src="/public/Apple.jpg" /> ← WARN が出力される
7
<img src="/src/assets/Banana.jpg" />
8
<img src="/src/content/blog/Cherry.jpg" />
9
10
<!-- 相対パス -->
11
<img src="../../public/Apple.jpg" /> ← WARN が出力される
12
<img src="../assets/Banana.jpg" /> ← 404 Not Found
13
<img src="../content/blog/Cherry.jpg" /> ← 404 Not Found

AstroJS では、import 文を用いて画像ファイルを読むことが出来ます。読み込まれた画像ファイルは、ImageMetadata 型のデータとして扱うことが出来ます。絶対パスで読み込んでも、相対パスで読み込んでも、挙動は同じです。また、<img> タグの src プロパティに直接、ファイルパスを設定する方法とは異なり、import localImage from '[ファイル名]' で読み込むことは出来ません。

src/pages/index.astro
1
---
2
// 正しい絶対パス
3
import localImage from '/public/Apple.jpg'
4
import localImage from '/src/assets/Banana.jpg'
5
import localImage from '/src/content/blog/Cherry.jpg'
6
7
// 正しい相対パス
8
import localImage from '../../public/Apple.jpg'
9
import localImage from '../assets/Banana.jpg'
10
import localImage from '../content/blog/Cherry.jpg'
11
12
// 誤ったパス
13
import localImage from 'Apple.jpg'
14
import localImage from '/Apple.jpg'
15
import localImage from './Apple.jpg'
16
---
17
18
<img src={localImage.src} width={localImage.width} height={localImage.height} />

3.2. <Image> コンポーネント

<img> タグを用いて表示される画像ファイルは、最適化が行われません 1 。画像を最適化したい場合は、<Image> コンポーネントを用いります。<Image> コンポーネントは、src プロパティと alt プロパティが必須です。更に詳しい仕様については、AstroJS の公式ドキュメント 1 を参照ください。

src/pages/index.astro
1
---
2
import { Image } from 'astro:assets'
3
4
import localImage from '/src/assets/Banana.jpg' // 絶対パス
5
or
6
import localImage from '../assets/Banana.jpg' // 相対パス
7
---
8
9
<Image src={localImage} alt="説明文" />

4. Markdown ファイル

4.1. コンテンツ部分

AstroJS では、src フォルダ内の Markdown ファイルは、自動的に HTML に変換されます。画像ファイルを絶対パスで指定しても、相対パスで指定しても、画像自体は表示されます。しかし、絶対パスで指定した場合は、最適化処理が行われません。一方、相対パスで指定した場合は、最適化されます。そのため、Markdown コンテンツ部分で画像を表示する場合は、相対パスで指定する方が良いと思います。

src/content/blog/first-post.md
1
# 絶対パス:最適化されない
2
![](/public/Apple.jpg) ← WARN が出力される
3
![](/src/assets/Banana.jpg)
4
![](/src/content/blog/Cherry.jpg)
5
6
# 相対パス:最適化される
7
![](../../../public/Apple.jpg)
8
![](../../assets/Banana.jpg)
9
![](Cherry.jpg)
10
![](/Cherry.jpg) ← 404 Not Found
11
![](./Cherry.jpg)

4.2. フロントマター部分

Markdown のフロントマター部分では、本文部分とは異なり、絶対パスで指定しても相対パスで指定しても最適化されます。ただし、Markdown ファイルと同じディレクトリに画像ファイルを配置する場合、heroImage: '[FILE]'heroImage: '/[FILE]' はエラーが発生するので注意が必要です。また、Markdown のフロントマターで設定した画像は、デフォルトでは最適化されません。Markdown のフロントマターで設定した画像を最適化する方法については、筆者の別記事 2 を参照ください。

src/content/blog/first-post.md
1
---
2
# 絶対パス:最適化される
3
heroImage: '/public/Apple.jpg' OK
4
heroImage: '/src/assets/Banana.jpg' OK
5
heroImage: '/src/content/blog/Cherry.jpg' OK
6
7
# 相対パス:最適化される
8
heroImage: '../../../public/Apple.jpg' OK
9
heroImage: '../../assets/Banana.jpg' OK
10
heroImage: 'Cherry.jpg' ERROR
11
heroImage: '/Cherry.jpg' ERROR
12
heroImage: './Cherry.jpg' OK
13
---

5. おわりに

ここまで、AstroJS における画像ファイルの読み込み挙動について、可能な限り網羅的に解説してきました。上記のコードは全て念入りにレビューしていますが、ヒューマンエラーで誤った情報がないとも限りません。また、AstroJS のアップデートで、仕様が変わる可能があります。何か、おかしな点がありましたら、連絡ください。

余談ですが、GatsbyJS の場合だと GraphQL が画像ファイルの読み込み処理を抽象化してくれていたので、ここまで難しい作業になりませんでした。あの憎かった GraphQL を再評価する日が来るとは思いませんでした。


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

  2. 【AstroJS】 Markdown のフロントマターで設定した画像を最適化する:https://xenexe.info/e360becc-d7d0-49f9-bf8b-0ee74430f50d/