Astroのアセットをdynamic importで読み込んで間接的な変数をなくす

Astroにおいて、コンポーネントから画像などのアセットを読み込む場合、import文を使うことが一般的だ。

---
import { Image } from 'astro:assets';
import logoImage from '../assets/logo.svg';
---

<Image src={logoImage} alt="Yuhei Yasuda" />

しかし、このような書き方をするとやや不便なことがある。それはimport文を使うと、実際にアセットを使用する箇所から離れた部分に記述が分散するため、一見して対応関係がわかりづらくなること。かつ、編集が面倒になる。例のように行数の少ないファイルではそれほどではないが、行数の多いファイルでは、離れた箇所に記述すると非常に煩わしいことになる。

そこで、代わりにdynamic importを使うことで、アセットの読み込みをインライン化することができる。<Image />コンポーネントのsrc propはPromiseに対応しているため、ここで直接dynamic importを使用できる。

---
import { Image } from 'astro:assets';
---

<Image src={import('../assets/logo.svg')} alt="Yuhei Yasuda" />

普通JavaScriptのアプリケーションでは、code splittingを有効にするためにdynamic importを使うが、この場合ではビルドへの影響はない。

ただし、Promiseの解決のためにawaitが必要な場合は都合が悪い。Astroコンポーネントにおいては、コードフェンスの外側ではawaitを使用できず、awaitはコードフェンスの内側に記述しなければならないからだ。したがって、直接パスを参照したければ、けっきょくは変数化せざるを得ない。

---
import { Image } from 'astro:assets';

const logoImage = (await import('../assets/logo.svg')).default;
---

<img src={logoImage.src} alt="Yuhei Yasuda" />

このような場合では、あえてdynamic importを使う理由はない。

一方、Astroコンポーネントではなく、MDXファイルの中ではawaitを使うことができる。そのため、dynamic importを活用した記述が可能である。

<video controls>
  <source src={(await import('./assets/video.webm')).default} type="video/webm" />
</video>