SvelteKitでサイトを作っていると、画像のファイルサイズや画面幅に応じた出し分けをどうするか悩むことが多々あります。
これまでは面倒だなと思いながらも事前に複数サイズ・複数のファイル形式で書き出しし、picture要素やsrcset属性でレスポンシブ画像を作っていました。
しかし何気なく読んでいたSvelteのドキュメントで、「@sveltejs/enhanced-img を使うと、ビルド時にローカル画像を自動変換し、複数形式・サイズの画像を用意できる」という驚愕の事実を知りました。
後進のために、enhanced-imgの基本的な使い方、ビルド時に行われる処理、どのようなプロジェクトに向いているかを備忘録としてまとめます。
enhanced-imgとは
@sveltejs/enhanced-img は、Viteのアセット処理に画像最適化を追加するプラグインです。SvelteKitだけでなく、Viteを使うSvelteプロジェクトで利用できます。
画像を指定するタグを <enhanced:img> にすると、ビルド時に画像を変換し、ブラウザや画面サイズに応じて適したファイルを選べるようにします。画像の幅と高さも元画像から読み取って設定するため、画像読み込み前のレイアウトずれを防ぐ助けになります。
導入方法
現在のSvelte CLIを使う場合は、プロジェクトのルートで次のコマンドを実行して追加できます。
npx sv add enhanced-img
このアドオンは、必要なパッケージとViteプラグインの設定をプロジェクトに追加します。
手動で設定する場合は @sveltejs/enhanced-img を開発依存関係に追加し、vite.config.js または vite.config.ts に enhancedImages() を登録します。
プラグインはSvelteKitより前に配置します(重要)。
import { enhancedImages } from '@sveltejs/enhanced-img';
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [
enhancedImages(),
sveltekit()
]
});
プロジェクトのSvelteKitやViteのバージョンによって設定が異なることがあるため、既存の vite.config に合わせて追加します。導入コマンドや設定は、公式ドキュメントの最新内容も確認してください。
基本的な使い方
Svelteコンポーネントで <img> の代わりに <enhanced:img> を使い、画像ファイルへのパスを指定します。
<enhanced:img
src="./images/coffee.jpg"
alt="カップに入ったコーヒー"
sizes="(min-width: 800px) 720px, 100vw"
/>
sizes属性を指定しておくと、自動でsrcset属性も設定されるので小さな画面に必要以上に大きなファイルが配信されるのを避けやすくなります。
画像を配列から選んだり、{#each} で繰り返し表示したりする場合は、画像を ?enhanced 付きでインポートします。
<script>
import coffee from './images/coffee.jpg?enhanced';
import tea from './images/tea.jpg?enhanced';
const products = [
{ name: 'コーヒー', image: coffee },
{ name: '紅茶', image: tea }
];
</script>
{#each products as product}
<enhanced:img src={product.image} alt={product.name} />
{/each}
内部ではどんな処理をしているか
細かい実装を覚えなくても、全体の流れは次のように捉えられます。
- ViteのプラグインがSvelteファイル内の
<enhanced:img>を見つける。 - 参照されたローカル画像を、ビルド時に画像処理ライブラリで変換する。
- 必要に応じてWebPやAVIFなどの形式や、画面に応じた複数のサイズを生成する。
- タグを、複数の画像候補を含む
<picture>と<img>を使ったHTMLに置き換える。 - ブラウザが対応形式や
srcset・sizesをもとに、表示に使う画像を選ぶ。 - 元画像から幅・高さを読み取り、HTMLに設定する。EXIF情報も取り除かれる。
そのため、利用者のアクセスごとにサーバー上で画像を変換するのではなく、あらかじめビルド成果物として画像を用意します。
最初のビルドでは画像変換の分だけ時間がかかることがあります。公式ドキュメントによると、変換結果はキャッシュされ、2回目以降のビルドでは処理を短縮できます。
どんなケースに向いているか
enhanced-imgが特に使いやすいのは、ビルド時点で画像ファイルがプロジェクト内にあり、どの画像を表示するか決まっているケースです。
- 静的サイトやブログの記事画像、サムネイル
- トップページや商品紹介ページのメインビジュアル
- プロジェクト内に置いたロゴ、イラスト、説明図
- あらかじめ分かっている画像一覧をページで出し分けるケース
つまり、静的サイト生成(SSG)とは非常に相性のよい用途です。ですがSSG専用の機能というわけではありません。
ポイントはレンダリング方式ではなく、画像がビルド時にローカルで参照できることです。SvelteKitのSSRページであっても、プロジェクト内に含まれビルド時に確定する画像なら利用できます。
向いていないケースと注意点
ビルド時に存在しない画像は、この方法では最適化できません。たとえば、CMSやデータベースから取得する画像、ユーザーがアップロードする画像、外部URLから都度取得する画像には、通常の <img> や画像CDNの変換機能などを検討します。
また、画像は基本的に縮小して使うため、表示したいサイズに対して十分な解像度の元画像を用意します。Retinaなどの高密度ディスプレイも想定する場合、表示寸法の約2倍の画像を用意するのが目安です。一方、画面いっぱいに表示する画像で sizes を指定しないと、小さな画面でも大きな候補が選ばれる可能性があるため、実際のレイアウトに合わせて指定します。
画像の幅・高さが自動設定されても、表示サイズをCSSで適切に制御することは必要です。
画像の内容が伝わる alt を設定し、ファーストビューの重要画像には遅延読み込みを設定しないなど、通常の画像表示に関する配慮も続けます。
まとめ
@sveltejs/enhanced-img は、プロジェクト内の画像をビルド時に最適化し、形式やサイズの異なる画像を配信しやすくするViteプラグインです。<enhanced:img> に置き換える基本的な使い方から始められ、静的サイトや、ビルド時に画像が確定しているページに向いています。
CMSやユーザー投稿など、実行時に決まる画像は別の仕組みを使います。画像の置き場所と更新方法に合わせて、ビルド時の最適化かCDNなどによる動的な最適化かを選ぶのがポイントです。
参考:SvelteKit公式ドキュメント「Images – @sveltejs/enhanced-img」/Svelte CLI公式ドキュメント「enhanced-img」

