0345

FE

[SvelteKit] Svelte 5 환경에서 Toast 적용기

| 서론

안녕하세요. 팡일입니다.

SvelteKit 기반 프로젝트 Re:Log를 개발하면서, “alert 대신 깔끔한 토스트 메시지를 띄워보자”는 생각이 들었는데요?


그래서 시작된, 예상보다 긴 “Toast 라이브러리 탐험기”를 공유해보려고 합니다.

| 첫 시도: svelte-french-toast

처음엔 가장 인기 있는 svelte-french-toast 패키지를 사용했습니다.

code
npm install svelte-french-toast

혹은 최신 버전을 명시하는 @latest 태그도 붙여보았습니다.

code
npm install svelte-french-toast@latest

하지만 어떤 명령어를 사용하든, 설치하자마자 다음 오류가 발생했습니다.

code
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.

사용 예시가 단순하고, 프로젝트 규모가 큰 만큼 믿을 만해 보였습니다.

CSS
npm install @zerodevx/svelte-toast

전역 레이아웃에 이렇게 추가했죠.

code
<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 환경에 맞게 직접 포팅한 버전이었습니다.


그리고 감사하게도, 이걸 설치하자 모든 게 깔끔하게 해결되었습니다.

code
npm install svelte-5-french-toast

| 적용 방법

공식 문서에서는 전역 레이아웃(+layout.svelte)에 Toaster를 등록하라고 되어 있습니다.

Svelte 5에서도 전역 등록이 정상적으로 작동합니다.

즉, 한 번만 추가하면 모든 하위 페이지에서 자동으로 토스트 메시지가 표시됩니다.

예를 들어, src/routes/+layout.svelte 파일에 다음처럼 작성하면 됩니다:

TypeScript
<script lang="ts">
	import { Toaster } from 'svelte-5-french-toast';
</script>

<slot />
<Toaster />

이제 개별 페이지에서 단순히 toast.success() toast.error()를 호출하기만 하면,
전역으로 설정된 Toaster를 통해 모든 페이지에서 동일한 스타일로 메시지가 출력됩니다.

아래와 같이 사용 가능합니다.

TypeScript
<script lang="ts">
	import toast from 'svelte-5-french-toast';

	function handleSave() {
		toast.success('저장되었습니다!');
	}
</script>

<button on:click={handleSave}>저장</button>

이 방식 덕분에 각 페이지마다 별도로 Toaster를 추가할 필요가 없으며,
전역적으로 일관된 UX를 유지할 수 있습니다.

| 실제 적용 예시 (Re:Log 마이페이지)

아래는 실제 적용된 코드 일부입니다.

HTML
<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는 잊어도 좋습니다.

한 줄이면 충분하니까요 ?

code
toast.success('저장되었습니다!');

참고 링크