SvelteKit 라우트를 연결하고, 레이아웃을 다듬고, 빌드를 배포하셨나요? 그런데 라이브 탭을 열면 기본 Svelte 로고가 보이거나, 더 나쁘게는 하얀 빈 사각형만 보일 수 있습니다. 이 문제는 대개 한 특정 파일, 즉 app.html에서 해결됩니다.

app.html은 SvelteKit이 서버와 클라이언트 양쪽에서 모든 페이지를 렌더링할 때 사용하는 HTML 셸입니다. SvelteKit 프로젝트 구조 문서에 따르면, 이 템플릿은 src/의 루트에 있으며, 모든 라우트에서 하이드레이션 후에도 유지되는 마크업을 주입할 수 있는 유일한 곳입니다. 따라서 파비콘 <link> 태그를 넣기에 가장 적합한 위치입니다.

왜 레이아웃이 아니라 app.html인가?

+layout.svelte 파일의 <svelte:head> 블록 안에 파비콘 태그를 추가할 수도 있으며, 대부분의 라우트에서 작동합니다. 그러나 app.html은 레이아웃이나 컴포넌트 코드가 실행되기 전에 먼저 렌더링됩니다. 이로 인해 두 가지 실질적인 이점이 있습니다:

사전 요구 사항

필요한 것은 다음과 같습니다:

아직 해당 파일이 없다면, Mzu favicondl을 사용하여 원본 이미지에서 생성하세요. 한 번의 클릭으로 전체 크기 패키지를 출력합니다.

단계별: app.html에 파비콘 링크 태그 추가하기

1. app.html 파일 찾기

src/app.html을 엽니다. 기본적으로 대략 다음과 같습니다:

<!doctype html>
<html lang='en'>
  <head>
    <meta charset='utf-8' />
    <link rel='icon' href='%sveltekit.assets%/favicon.png' />
    <meta name='viewport' content='width=device-width, initial-scale=1' />
    %sveltekit.head%
  </head>
  <body data-sveltekit-preload-data='hover'>
    <div style='display: contents'>%sveltekit.body%</div>
  </body>
</html>

%sveltekit.assets%와 %sveltekit.head% 플레이스홀더는 빌드 시 대체됩니다. 이들을 유지하고 위나 아래에 태그를 추가할 수 있습니다.

2. 기본 파비콘 줄 교체

스타터 템플릿에는 단일 favicon.png 줄이 포함되어 있습니다. 이를 삭제하고 전체 태그 세트로 교체하세요. HTML 사양은 rel='icon'을 아이콘 선언의 표준 방법으로 정의하므로 해당 속성을 사용하세요.

<link rel='icon' href='%sveltekit.assets%/favicon.svg' type='image/svg+xml' />
<link rel='icon' href='%sveltekit.assets%/favicon.ico' sizes='32x32' />
<link rel='apple-touch-icon' href='%sveltekit.assets%/apple-touch-icon.png' sizes='180x180' />
<link rel='manifest' href='%sveltekit.assets%/site.webmanifest' />

SVG를 먼저 배치하여 최신 브라우저가 선호하도록 합니다. ICO는 이전 브라우저를 위한 폴백 역할을 합니다. Apple Touch와 manifest는 특정 플랫폼을 대상으로 하므로 마지막에 둡니다.

3. 다크 모드 지원 추가

SVG 아이콘이 다크 탭에서 다른 모양을 필요로 한다면(요즘 다크 테마를 사용하지 않는 사람이 있을까요?), 두 개의 미디어별 소스를 선언하세요. 이는 파비콘 다크 모드 가이드에서 다루는 것과 동일한 기술입니다:

<link rel='icon' href='%sveltekit.assets%/favicon-light.svg' type='image/svg+xml' media='(prefers-color-scheme: light)' />
<link rel='icon' href='%sveltekit.assets%/favicon-dark.svg' type='image/svg+xml' media='(prefers-color-scheme: dark)' />

브라우저는 media 속성을 평가하여 일치하는 아이콘을 선택합니다.

4. static/에 파일 넣기

SvelteKit은 static/ 안의 모든 것을 사이트 루트에서 제공합니다. 각 파비콘 파일을 태그에서 참조한 정확한 파일 이름으로 해당 위치에 배치하세요. 깔끔한 구조는 다음과 같습니다:

static/
├── favicon.svg
├── favicon.ico
├── favicon-light.svg
├── favicon-dark.svg
├── apple-touch-icon.png
└── site.webmanifest

5. 개발 서버 재시작

Vite는 HTML 셸을 적극적으로 캐시합니다. app.html을 편집한 후에는 Ctrl+C로 개발 서버를 중지하고 npm run dev를 다시 실행하세요. 그렇지 않으면 이전 마크업이 계속 표시될 수 있습니다.

흔한 함정

파비콘 태그를 body에 넣는 경우. 브라우저는 아이콘 선언을 위해 <head>만 확인합니다. <body> 안의 내용은 파일 이름이 app.html이더라도 무시됩니다. 파비콘이 나타나지 않는다면 가장 먼저 확인할 사항입니다.

태그와 static/의 파일 이름 불일치. Linux 배포에서는 대소문자 구분이 중요합니다. favicon.ICO와 favicon.ico는 다른 파일입니다. 이름을 정확히 일치시키세요.

배포 후 오래된 아이콘. 브라우저는 파비콘을 적극적으로 캐시하며 때로는 몇 주 동안 유지합니다. 파일을 교체했는데 업데이트가 보이지 않으면 쿼리 문자열이나 콘텐츠 해시를 추가한 후 다시 배포하세요. 이 패턴은 static/의 모든 정적 자산에 동일하게 적용됩니다.

SVG 속성의 이중 인코딩. type="image/svg+xml"처럼 큰따옴표를 사용하는 스니펫을 app.html 셸에 복사하면 Vite가 망가뜨릴 수 있습니다. HTML 속성에는 작은따옴표를 사용하여 빌드가 정상 작동하도록 하세요.

마무리

app.html 템플릿은 JavaScript보다 먼저 실행되고 모든 페이지 응답에 포함되므로 SvelteKit에서 파비콘을 선언하는 가장 깔끔한 위치입니다. 완전한 SVG + ICO + Apple Touch 스택을 static/에 넣고 해당 <link> 태그를 <head>에 연결하면 첫 페인트부터 모든 브라우저 탭에 선명한 아이콘이 표시됩니다.

SvelteKit 파비콘 옵션에 대한 더 넓은 시각(+layout.svelte 접근 방식 및 동적 아이콘 포함)은 메인 SvelteKit 파비콘 가이드를 참조하세요. 실제 아이콘 파일이 필요하다면 Mzu favicondl이 원본 이미지에서 전체 크기 스택을 몇 초 만에 생성합니다.