FE
[SvelteKit] Svelte 5 환경에서 Toast 적용기
| 서론
안녕하세요. 팡일입니다.
SvelteKit 기반 프로젝트 Re:Log를 개발하면서, “alert 대신 깔끔한 토스트 메시지를 띄워보자”는 생각이 들었는데요?
그래서 시작된, 예상보다 긴 “Toast 라이브러리 탐험기”를 공유해보려고 합니다.
| 첫 시도: svelte-french-toast
처음엔 가장 인기 있는 svelte-french-toast 패키지를 사용했습니다.
npm install svelte-french-toast혹은 최신 버전을 명시하는 @latest 태그도 붙여보았습니다.
npm install svelte-french-toast@latest하지만 어떤 명령어를 사용하든, 설치하자마자 다음 오류가 발생했습니다.
npm ERR! peer svelte@"^3.57.0 || ^4.0.0" from svelte-french-toast@1.2.0
npm ERR! Found: svelte@5.43.5원인은 명확했습니다.
NPM에 @latest (최신 안정화 버전)로 등록된 svelte-french-toast의 버전이 Svelte 3/4만 지원하는 v1.2.0이었던 것입니다.
즉, "Svelte 5 프로젝트에서는 표준적인 방법(npm install ...)으로는 설치조차 되지 않았습니다."
(나중에 더 깊이 탐험하며 알게 된 사실이지만, Svelte 5를 지원하는 2.0.0-alpha.0 버전이 존재하긴 했습니다. 하지만 이는 정식 배포 버전이 아니라서, @latest 태그로 설치되지 않았던 것입니다.)
| 두 번째 시도: @zerodevx/svelte-toast
두 번째 후보는 @zerodevx/svelte-toast.
사용 예시가 단순하고, 프로젝트 규모가 큰 만큼 믿을 만해 보였습니다.
npm install @zerodevx/svelte-toast전역 레이아웃에 이렇게 추가했죠.
<script>
import { SvelteToast } from '@zerodevx/svelte-toast';
</script>
<slot />
<SvelteToast />하지만... 결과는 화면에 아무것도 안 뜨는 상황을 마주해야 했습니다.
콘솔엔 에러도 없고, 메시지도 표시되지 않았습니다.
알고 보니, Svelte 5의 새로운 렌더링 구조와 맞지 않아 마운트가 안 되는 문제였습니다.
즉, @zerodevx/svelte-toast도 Svelte 5와는 완전 호환되지 않았던 것이죠.
| 최종 해결: svelte-5-french-toast
이후 GitHub에서 발견한 해결책이 바로
? svelte-5-french-toast
이건 기존 svelte-french-toast를 Svelte 5 환경에 맞게 직접 포팅한 버전이었습니다.
그리고 감사하게도, 이걸 설치하자 모든 게 깔끔하게 해결되었습니다.
npm install svelte-5-french-toast| 적용 방법
공식 문서에서는 전역 레이아웃(+layout.svelte)에 Toaster를 등록하라고 되어 있습니다.
Svelte 5에서도 전역 등록이 정상적으로 작동합니다.
즉, 한 번만 추가하면 모든 하위 페이지에서 자동으로 토스트 메시지가 표시됩니다.
예를 들어, src/routes/+layout.svelte 파일에 다음처럼 작성하면 됩니다:
<script lang="ts">
import { Toaster } from 'svelte-5-french-toast';
</script>
<slot />
<Toaster />이제 개별 페이지에서 단순히 toast.success()나 toast.error()를 호출하기만 하면,
전역으로 설정된 Toaster를 통해 모든 페이지에서 동일한 스타일로 메시지가 출력됩니다.
아래와 같이 사용 가능합니다.
<script lang="ts">
import toast from 'svelte-5-french-toast';
function handleSave() {
toast.success('저장되었습니다!');
}
</script>
<button on:click={handleSave}>저장</button>이 방식 덕분에 각 페이지마다 별도로 Toaster를 추가할 필요가 없으며,
전역적으로 일관된 UX를 유지할 수 있습니다.
| 실제 적용 예시 (Re:Log 마이페이지)
아래는 실제 적용된 코드 일부입니다.
<script lang="ts">
import toast, { Toaster } from 'svelte-5-french-toast';
import { Loader2 } from 'lucide-svelte';
let isSaving = false;
async function handleUpdate() {
isSaving = true;
try {
// Firestore 업데이트 로직
toast.success('프로필이 수정되었습니다!');
} catch (error) {
toast.error('프로필 수정 중 오류가 발생했습니다.');
} finally {
isSaving = false;
}
}
</script>
<button on:click={handleUpdate} disabled={isSaving}>
{#if isSaving}
<Loader2 class="h-5 w-5 animate-spin" />
{:else}
저장
{/if}
</button>
<Toaster />결과적으로,
저장 성공 시 toast.success('프로필이 수정되었습니다!')
실패 시 toast.error('오류 발생') 이 깔끔하게 표시됩니다.
| 결론
이제 alert는 잊어도 좋습니다.
한 줄이면 충분하니까요 ?
toast.success('저장되었습니다!');참고 링크