Cours Svelte et SvelteKit · Module 11: Routage SvelteKit

Pages d'erreur et pages spéciales

2 min de lecture ·
Dans cette leçon4

+error.svelte

<!-- src/routes/+error.svelte -->
<script>
  import { page } from '$app/state';
</script>

<h1>Erreur {page.status}</h1>
<p>{page.error?.message}</p>

<a href="/">Retour à la page d'accueil</a>

L'objet page de $app/state est réactif et tu le lis sans signe $. L'ancien store $page du module $app/stores a été supprimé dans SvelteKit 3.

Signaler des erreurs

// src/routes/warriors/[id]/+page.js
import { error } from '@sveltejs/kit';

export function load({ params }) {
  const warrior = getWarrior(params.id);

  if (!warrior) {
    error(404, 'Guerrier introuvable');
  }

  return { warrior };
}

La fonction error() lève l'exception elle-même : tu n'écris donc pas throw devant (c'était la forme de SvelteKit 1). Le deuxième argument est toujours le texte du message.

+page.js vs +page.server.js

// +page.js - s'exécute sur le serveur ET le client
export function load({ params, fetch }) {
  // Peut être appelé pendant la navigation côté client
  return { data };
}
// +page.server.js - serveur UNIQUEMENT
export function load({ params, locals }) {
  // Accès à la base de données, aux secrets, etc.
  return { data };
}

Redirections

import { redirect } from '@sveltejs/kit';

export function load({ locals }) {
  if (!locals.user) {
    redirect(303, '/login');
  }

  return { user: locals.user };
}

Comme error(), la fonction redirect() lève l'exception elle-même, sans throw.

Code de cette leçon : App.svelte
<script>
  // Navigation programmatique et états de chargement

  let loading = $state(false);
  let currentPage = $state('home');

  async function navigateTo(page) {
    loading = true;

    // Simulation du chargement des données
    await new Promise(r => setTimeout(r, 1000));

    currentPage = page;
    loading = false;
  }

  // Simulation de beforeNavigate
  function handleBeforeNavigate(e, page) {
    if (currentPage === 'form' && !confirm('Quitter la page ?')) {
      e.preventDefault();
      return;
    }
    navigateTo(page);
  }
</script>

<main class="navigation-demo">
  <h1>Navigation SvelteKit</h1>

  <nav class="nav">
    <button onclick={(e) => handleBeforeNavigate(e, 'home')}>Accueil</button>
    <button onclick={(e) => handleBeforeNavigate(e, 'warriors')}>Guerriers</button>
    <button onclick={(e) => handleBeforeNavigate(e, 'form')}>Formulaire</button>
  </nav>

  {#if loading}
    <div class="loading">
      <div class="spinner"></div>
      <p>Chargement...</p>
    </div>
  {:else}
    <section class="content">
      {#if currentPage === 'home'}
        <h2>Page d’accueil</h2>
        <p>Bienvenue dans l’appli !</p>
      {:else if currentPage === 'warriors'}
        <h2>Guerriers</h2>
        <p>Liste chargée depuis le serveur</p>
      {:else if currentPage === 'form'}
        <h2>Formulaire</h2>
        <p>Quitter entraînera une perte de données !</p>
        <input placeholder="Écris quelque chose..." />
      {/if}
    </section>
  {/if}

  <section class="code-example">
    <h2>Navigation programmatique</h2>
    <pre>
import {"{"} goto {"}"} from '$app/navigation';

// Navigation simple
goto('/warriors');

// Avec options
goto('/warriors', {"{"}
  replace: true,
  refreshAll: true
{"}"});
    </pre>
  </section>
</main>

<style>
  .navigation-demo {
    font-family: 'Georgia', serif;
    max-width: 600px;
    margin: 0 auto;
    padding: 2rem;
    background: #0a1628;
    color: #b8d4f7;
    min-height: 100vh;
  }

  h1 {
    color: #4a90d9;
    text-align: center;
  }

  .nav {
    display: flex;
    justify-content: center;
    gap: 0.5rem;
    margin-bottom: 2rem;
  }

  button {
    padding: 0.75rem 1.5rem;
    background: #1e3a5f;
    color: #b8d4f7;
    border: 1px solid #4a90d9;
    border-radius: 4px;
    cursor: pointer;
  }

  button:hover {
    background: #2a4a6f;
  }

  .loading {
    text-align: center;
    padding: 3rem;
  }

  .spinner {
    width: 50px;
    height: 50px;
    border: 4px solid #1e3a5f;
    border-top-color: #4a90d9;
    border-radius: 50%;
    animation: spin 1s linear infinite;
    margin: 0 auto 1rem;
  }

  @keyframes spin {
    to { transform: rotate(360deg); }
  }

  section {
    background: rgba(74, 144, 217, 0.1);
    border: 1px solid #4a90d9;
    border-radius: 8px;
    padding: 1rem;
    margin: 1rem 0;
  }

  h2 {
    color: #4a90d9;
    margin-top: 0;
  }

  input {
    width: 100%;
    padding: 0.75rem;
    background: rgba(0,0,0,0.3);
    border: 1px solid #4a90d9;
    border-radius: 4px;
    color: #b8d4f7;
    margin-top: 0.5rem;
  }

  pre {
    background: rgba(0,0,0,0.5);
    padding: 1rem;
    border-radius: 4px;
    font-size: 0.85rem;
    overflow-x: auto;
  }
</style>

Entrées de la documentation utilisées dans cette leçon

Tu as repéré une erreur dans cette leçon ?

Teste tes connaissances

Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.

  1. 1. Comment signaler une erreur 404 dans la fonction load (SvelteKit 3) ?

Articles utiles