画像やアイコンは/staticか$lib/assetsか、配置先の使い分け
SvelteKitのプロジェクトで画像やアイコンを置く場所として、プロジェクトルートのstatic/と、src/lib/assets/の2つの選択肢があります。どちらに置いてもとりあえず表示自体はできてしまうため、初見では違いが分かりにくいのですが、Viteによるビルド処理を通すかどうかという決定的な違いがあります。
static/はそのままコピーされるだけ
static/配下に置いたファイルは、ビルド時に一切加工されず、そのままの内容・そのままのファイル名でビルド出力のルートにコピーされます。
<link rel="icon" href="/favicon.png" />
<meta property="og:image" content="https://example.com/images/ogp-image.png" />このため、favicon画像やrobots.txt、OGP画像のように、URL文字列として決まったパスで参照する必要があるファイルはstatic/に置きます。<meta>タグのcontent属性やmanifestファイルのように、Svelteコンポーネントのimport文を経由しない箇所から参照する場合、Viteのビルド処理でファイル名にハッシュが付与されてしまうと参照が壊れてしまうため、加工されないstatic/が適しています。
$lib/assetsはimportすることでVite処理の対象になる
一方src/lib/assets/に置いた画像は、コンポーネント側でimportすることでVite(および@sveltejs/enhanced-imgの?enhancedクエリ)による最適化の対象になります。
<script>
import productImg from '$lib/assets/product-screenshot.jpg?enhanced';
</script>
<enhanced:img src={productImg} alt="製品画面" />?enhancedを付けてimportすると、ビルド時に画像がAVIF・WebPを含む複数フォーマット・複数解像度に変換され、<img>のsrcset・width・heightが自動で生成されます。レスポンシブ対応や配信サイズの最適化を手動で行う必要がなくなる一方、この最適化はコンポーネントのimport文経由でVite解決できるファイルにしか適用できません。加えて、出力ファイル名にはコンテンツハッシュが付与されるため、ファイルを更新した際にブラウザキャッシュを気にする必要がないというメリットもあります。
余談: SVGアイコンはSvelteコンポーネントとして展開することもできる
$lib/assetsにSVGアイコンを置く場合、@poppanator/sveltekit-svgのような専用のViteプラグインを使うと、SVGファイルを画像パスとしてではなく、Svelteコンポーネントとしてそのままインポートすることもできます。
<script>
import IconArrow from '$lib/assets/icon-arrow.svg?component';
</script>
<IconArrow class="icon" />こうするとSVGの中身がマークアップにインラインで展開されるため、CSSのcurrentColorと連動させて塗りの色をテーマに合わせて変えたり、内部の特定のパスだけにクラスを当てて部分的にアニメーションさせたりと、SVG構造そのものへ介入できるようになります。単なる装飾画像ではなく、色や状態に応じて見た目を変えたいアイコン類を扱う場面では、こちらの方法も選択肢に入れておくと便利です。
判断基準
置き場所に迷ったときの基準はシンプルです。
<meta>タグ・manifest・CSSのbackground-image: url(...)のように、文字列としてURLパスを直接書く必要がある →static/- Svelteコンポーネントの中で
<img>・<enhanced:img>として表示し、最適化やキャッシュバスティングの恩恵を受けたい →$lib/assets
背景画像やロゴのようにサイト全体で使い回すファイル、外部から絶対パスで参照される可能性があるファイルはstatic/に、個別ページのコンテンツ画像のようにコンポーネントの内側で完結するファイルは$lib/assetsに置く、という切り分けが基本になります。
まとめ
static/と$lib/assetsはどちらも「画像を置く場所」という点では同じに見えますが、Viteのビルド処理を通すかどうかがまったく異なります。URLパスとして直接参照する必要があるファイルはstatic/、コンポーネントのimportを通して最適化の恩恵を受けたいファイルは$lib/assets、という基準で使い分けることで、意図せずキャッシュや最適化の恩恵を取りこぼすことを防げます。