feat(scaffold): add Axum + Leptos SSR base structure
Sets up the full project skeleton: Cargo.toml with ssr/hydrate features, Axum server entry point, shared Leptos lib, root App component with router, server/client module split, and Trunk config for WASM build. Both `cargo check --features ssr` and `cargo check --features hydrate --target wasm32-unknown-unknown` pass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2691
Cargo.lock
generated
2691
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
73
Cargo.toml
73
Cargo.toml
@@ -1,6 +1,77 @@
|
||||
[package]
|
||||
name = "rust-ipam"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
edition = "2021"
|
||||
|
||||
# Leptos nécessite deux formats de compilation :
|
||||
# - rlib : bibliothèque normale, utilisée par le serveur Axum
|
||||
# - cdylib : bibliothèque dynamique compilée en WebAssembly pour le navigateur
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
# Les "features" permettent d'activer du code conditionnellement selon le contexte.
|
||||
# On compile deux fois le même code : une fois en mode "ssr" (serveur), une fois "hydrate" (WASM).
|
||||
[features]
|
||||
# Mode serveur : active Axum, Tokio, et le rendu HTML côté serveur
|
||||
ssr = [
|
||||
"dep:axum",
|
||||
"dep:tokio",
|
||||
"dep:tower-http",
|
||||
"dep:leptos_axum",
|
||||
"dep:tracing-subscriber",
|
||||
"leptos/ssr",
|
||||
"leptos_meta/ssr",
|
||||
"leptos_router/ssr",
|
||||
]
|
||||
# Mode client : compile l'application en WebAssembly pour le navigateur
|
||||
# Note : seul `leptos` expose une feature "hydrate" ; leptos_meta et leptos_router
|
||||
# n'en ont pas besoin — ils s'adaptent automatiquement au mode de compilation.
|
||||
hydrate = [
|
||||
"dep:console_error_panic_hook",
|
||||
"dep:wasm-bindgen",
|
||||
"leptos/hydrate",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
# --- Dépendances partagées (compilées côté serveur ET client) ---
|
||||
|
||||
# Framework UI réactif full-stack : le cœur du projet
|
||||
leptos = { version = "0.7", features = [] }
|
||||
# Gestion des balises HTML <head> (title, meta tags, liens CSS...)
|
||||
leptos_meta = { version = "0.7", features = [] }
|
||||
# Routeur : associe des URLs à des composants, côté serveur et client
|
||||
leptos_router = { version = "0.7", features = [] }
|
||||
|
||||
# Dérive automatiquement des types d'erreurs idiomatiques Rust
|
||||
thiserror = "1"
|
||||
# Macros pour les logs : tracing::info!(), tracing::error!()...
|
||||
tracing = "0.1"
|
||||
|
||||
# --- Dépendances serveur uniquement (activées par la feature "ssr") ---
|
||||
|
||||
# Serveur HTTP asynchrone rapide et ergonomique
|
||||
axum = { version = "0.7", optional = true }
|
||||
# Runtime asynchrone Rust (nécessaire pour `async fn main()` et les Futures)
|
||||
tokio = { version = "1", features = ["full"], optional = true }
|
||||
# Pont entre Leptos et Axum : SSR, server functions, streaming...
|
||||
leptos_axum = { version = "0.7", optional = true }
|
||||
# Middleware HTTP : sert les fichiers statiques (CSS, WASM compilé, images...)
|
||||
tower-http = { version = "0.5", features = ["fs"], optional = true }
|
||||
# Formateur de logs pour le terminal (affiche les messages tracing::info!...)
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"], optional = true }
|
||||
|
||||
# --- Dépendances client uniquement (activées par la feature "hydrate") ---
|
||||
|
||||
# Affiche les panics Rust dans la console du navigateur (indispensable pour déboguer)
|
||||
console_error_panic_hook = { version = "0.1", optional = true }
|
||||
# Pont entre Rust/WASM et JavaScript : permet d'appeler du JS depuis Rust
|
||||
wasm-bindgen = { version = "0.2", optional = true }
|
||||
|
||||
# Profil de compilation WASM optimisé pour réduire la taille du fichier .wasm
|
||||
# Un fichier WASM plus petit = page qui charge plus vite
|
||||
[profile.wasm-release]
|
||||
inherits = "release"
|
||||
opt-level = "z" # Optimise pour la taille (z) plutôt que la vitesse (3)
|
||||
lto = true # Link-Time Optimization : élimine le code mort entre crates
|
||||
codegen-units = 1 # Un seul thread de codegen = meilleure optimisation globale
|
||||
panic = "abort" # Pas de stack unwinding = binaire plus petit
|
||||
|
||||
25
Trunk.toml
Normal file
25
Trunk.toml
Normal file
@@ -0,0 +1,25 @@
|
||||
# Trunk.toml — Configuration de trunk
|
||||
# trunk est l'outil de build pour les applications Rust/WASM.
|
||||
#
|
||||
# Commandes principales :
|
||||
# trunk serve → serveur de dev avec hot-reload (recompile à chaque changement)
|
||||
# trunk build → compilation production (dans target/site/)
|
||||
# trunk build --release → compilation production optimisée (avec profile wasm-release)
|
||||
|
||||
[build]
|
||||
# Feature à activer lors de la compilation WASM
|
||||
# "hydrate" active le code client et désactive le code serveur
|
||||
features = ["hydrate"]
|
||||
# Dossier de sortie des fichiers compilés (JS, WASM, CSS, HTML)
|
||||
dist = "target/site"
|
||||
|
||||
[watch]
|
||||
# Dossiers à ignorer lors de la surveillance des changements de fichiers
|
||||
# Sans ça, trunk se relancerait en boucle en détectant ses propres fichiers compilés
|
||||
ignore = ["./target"]
|
||||
|
||||
[serve]
|
||||
# Port du serveur de développement trunk
|
||||
port = 3000
|
||||
# Ne pas ouvrir le navigateur automatiquement au démarrage
|
||||
open = false
|
||||
25
index.html
Normal file
25
index.html
Normal file
@@ -0,0 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<!--
|
||||
trunk complète automatiquement ce fichier lors de `trunk build` ou `trunk serve` :
|
||||
- Il injecte les balises <link> pour charger le CSS compilé
|
||||
- Il injecte les balises <script> pour charger le bundle WebAssembly
|
||||
Ne pas ajouter ces balises manuellement ici — trunk le fait pour vous.
|
||||
-->
|
||||
</head>
|
||||
<body>
|
||||
<!--
|
||||
Leptos monte l'application ici via mount_to_body() (défini dans lib.rs).
|
||||
|
||||
Flux SSR + Hydration :
|
||||
1. Le navigateur demande la page au serveur Axum
|
||||
2. Axum rend le composant App() en HTML (SSR) et l'envoie
|
||||
3. Le navigateur affiche le HTML instantanément (pas d'écran blanc)
|
||||
4. Le bundle WASM se charge en arrière-plan
|
||||
5. Leptos "hydrate" le HTML : attache les event listeners pour le rendre interactif
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
62
src/app.rs
Normal file
62
src/app.rs
Normal file
@@ -0,0 +1,62 @@
|
||||
// app.rs — Composant racine de l'application Leptos
|
||||
//
|
||||
// Ce composant est le point d'entrée de toute l'interface.
|
||||
// Il définit :
|
||||
// - Les métadonnées globales (title, CSS...)
|
||||
// - Le routeur : quelle page afficher selon l'URL
|
||||
// - Les contextes globaux partagés (à ajouter plus tard : auth, thème...)
|
||||
|
||||
use leptos::prelude::*;
|
||||
use leptos_meta::*;
|
||||
use leptos_router::{
|
||||
components::{Route, Router, Routes},
|
||||
path,
|
||||
};
|
||||
|
||||
use crate::client::home::HomePage;
|
||||
|
||||
// `#[component]` est un attribut procédural Leptos.
|
||||
// Il transforme une fonction Rust normale en composant réutilisable et traçable.
|
||||
//
|
||||
// Règle de nommage : toujours PascalCase pour les composants Leptos.
|
||||
//
|
||||
// `-> impl IntoView` : la fonction retourne "quelque chose affichable".
|
||||
// On utilise `impl` (type opaque) car le type exact généré par `view!` est complexe.
|
||||
#[component]
|
||||
pub fn App() -> impl IntoView {
|
||||
// Initialise le contexte de métadonnées Leptos.
|
||||
// Sans cet appel, les composants <Title>, <Meta>, <Stylesheet> plus bas ne fonctionnent pas.
|
||||
provide_meta_context();
|
||||
|
||||
// La macro `view!` permet d'écrire du HTML dans du Rust.
|
||||
// Leptos la transforme en code Rust pur à la compilation — pas de runtime template engine.
|
||||
view! {
|
||||
// Définit le titre de l'onglet navigateur (injecté dans le <head> HTML)
|
||||
<Title text="Rust IPAM — Gestionnaire d'adresses IP"/>
|
||||
|
||||
// Charge le CSS global. Le nom de fichier suit la convention Leptos :
|
||||
// `{nom-du-crate}.css` dans le dossier `/pkg/` servi par Axum.
|
||||
<Stylesheet id="main" href="/pkg/rust-ipam.css"/>
|
||||
|
||||
// Le Router gère la navigation côté client sans rechargement de page.
|
||||
// Côté serveur (SSR), il détermine quel composant rendre selon l'URL demandée.
|
||||
<Router>
|
||||
<main>
|
||||
// `<Routes>` est le conteneur pour toutes les définitions de routes.
|
||||
// `fallback` est affiché si aucune route ne correspond à l'URL actuelle.
|
||||
<Routes fallback=|| view! {
|
||||
<div class="page-erreur">
|
||||
<h1>"404 — Page introuvable"</h1>
|
||||
<a href="/">"← Retour à l'accueil"</a>
|
||||
</div>
|
||||
}>
|
||||
// Chaque `<Route>` associe un chemin URL à un composant.
|
||||
// `path!(/)` correspond exactement à l'URL racine "/".
|
||||
// Ajouter de nouvelles pages ici, exemple :
|
||||
// <Route path=path!("/reseaux") view=ReseauxPage/>
|
||||
<Route path=path!("/") view=HomePage/>
|
||||
</Routes>
|
||||
</main>
|
||||
</Router>
|
||||
}
|
||||
}
|
||||
78
src/client/home.rs
Normal file
78
src/client/home.rs
Normal file
@@ -0,0 +1,78 @@
|
||||
// client/home.rs — Page d'accueil
|
||||
//
|
||||
// Ce fichier illustre les concepts fondamentaux de Leptos :
|
||||
// - Composants (`#[component]`)
|
||||
// - Signals (valeurs réactives)
|
||||
// - Memos (valeurs dérivées)
|
||||
// - Gestion d'événements (`on:click`)
|
||||
|
||||
use leptos::prelude::*;
|
||||
|
||||
// Composant de la page d'accueil.
|
||||
//
|
||||
// En Leptos, un composant est une simple fonction Rust avec l'attribut `#[component]`.
|
||||
// Elle est appelée une seule fois pour construire le graphe réactif —
|
||||
// ce n'est pas comme React où le composant se "ré-exécute" à chaque mise à jour.
|
||||
#[component]
|
||||
pub fn HomePage() -> impl IntoView {
|
||||
// `RwSignal<T>` (Read-Write Signal) est une valeur réactive mutable.
|
||||
//
|
||||
// Quand on appelle `.set()` ou `.update()`, Leptos identifie automatiquement
|
||||
// tous les éléments du DOM qui dépendent de ce signal et les met à jour —
|
||||
// sans Virtual DOM, sans diff complet : seulement ce qui change.
|
||||
//
|
||||
// `i32` = entier signé 32 bits (le type entier par défaut en Rust)
|
||||
let compteur = RwSignal::new(0i32);
|
||||
|
||||
// `Memo<T>` est une valeur calculée à partir d'un ou plusieurs signals.
|
||||
// Elle se recalcule automatiquement quand `compteur` change, mais
|
||||
// ne notifie ses dépendants que si sa valeur a effectivement changé.
|
||||
//
|
||||
// `move |_|` : une closure qui capture `compteur` par déplacement (ownership).
|
||||
// - `move` : la closure prend possession de `compteur`
|
||||
// - `|_|` : elle ignore son argument (la valeur précédente du memo)
|
||||
let double = Memo::new(move |_| compteur.get() * 2);
|
||||
|
||||
view! {
|
||||
<div class="page-accueil">
|
||||
<h1>"Rust IPAM"</h1>
|
||||
<p class="sous-titre">"Gestionnaire d'adresses IP"</p>
|
||||
|
||||
// --- Démonstration de la réactivité ---
|
||||
// Dans un vrai projet IPAM, on afficherait ici la liste des sous-réseaux,
|
||||
// les adresses disponibles, les statistiques d'utilisation...
|
||||
<section class="demo-reactive">
|
||||
<h2>"Réactivité Leptos"</h2>
|
||||
|
||||
// `{compteur}` insère la valeur du signal directement dans le DOM.
|
||||
// Leptos met à jour UNIQUEMENT ce nœud texte quand compteur change.
|
||||
// Pas de re-render du composant entier : c'est granulaire et efficace.
|
||||
<p>"Compteur : " {compteur}</p>
|
||||
|
||||
// `{double}` : idem, mais pour le memo (valeur dérivée)
|
||||
<p>"Double : " {double}</p>
|
||||
|
||||
<div class="boutons">
|
||||
// `on:click` attache un event listener au bouton.
|
||||
//
|
||||
// `.update(|n| *n += 1)` :
|
||||
// - prend une closure qui reçoit une référence mutable `&mut i32`
|
||||
// - `*n` déréférence le pointeur pour modifier la valeur pointée
|
||||
// - `+= 1` incrémente la valeur en place
|
||||
<button on:click=move |_| compteur.update(|n| *n += 1)>
|
||||
"+"
|
||||
</button>
|
||||
|
||||
<button on:click=move |_| compteur.update(|n| *n -= 1)>
|
||||
"-"
|
||||
</button>
|
||||
|
||||
// `.set(0)` remplace directement la valeur (plus simple qu'update ici)
|
||||
<button on:click=move |_| compteur.set(0)>
|
||||
"Réinitialiser"
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
12
src/client/mod.rs
Normal file
12
src/client/mod.rs
Normal file
@@ -0,0 +1,12 @@
|
||||
// client/mod.rs — Module client (composants UI)
|
||||
//
|
||||
// Contient les pages et composants Leptos de l'application.
|
||||
//
|
||||
// Important : malgré le nom "client", ce code s'exécute des DEUX côtés :
|
||||
// - Côté serveur : pour générer le HTML initial (SSR)
|
||||
// - Côté navigateur : compilé en WASM pour rendre l'interface interactive
|
||||
//
|
||||
// Ne pas mettre ici de code qui nécessite des APIs navigateur (window, document...)
|
||||
// sans le protéger avec `#[cfg(target_arch = "wasm32")]`.
|
||||
|
||||
pub mod home; // Page d'accueil
|
||||
40
src/lib.rs
Normal file
40
src/lib.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
// lib.rs — Racine de la bibliothèque partagée
|
||||
//
|
||||
// Ce fichier est compilé dans les DEUX modes :
|
||||
// "ssr" → le serveur Axum l'utilise pour rendre du HTML
|
||||
// "hydrate" → trunk le compile en WebAssembly pour le navigateur
|
||||
//
|
||||
// C'est ce partage de code qui rend Leptos "full-stack" :
|
||||
// on écrit les composants une fois, ils s'exécutent des deux côtés.
|
||||
|
||||
// Déclaration des sous-modules de cette bibliothèque.
|
||||
// `pub` les rend accessibles depuis main.rs et d'autres crates.
|
||||
pub mod app; // Composant racine App() et configuration du routeur
|
||||
pub mod client; // Pages et composants de l'interface utilisateur
|
||||
pub mod server; // Handlers HTTP et logique métier côté serveur
|
||||
|
||||
// Point d'entrée WebAssembly — exécuté par le navigateur au chargement du bundle .wasm
|
||||
//
|
||||
// `#[cfg(feature = "hydrate")]` : ce code n'existe que dans le bundle WASM.
|
||||
// `#[wasm_bindgen(start)]` : demande à wasm-bindgen d'appeler cette fonction
|
||||
// automatiquement sans intervention JavaScript.
|
||||
#[cfg(feature = "hydrate")]
|
||||
#[wasm_bindgen::prelude::wasm_bindgen(start)]
|
||||
pub fn hydrate() {
|
||||
use crate::app::App;
|
||||
|
||||
// Active les messages d'erreur Rust dans la console du navigateur.
|
||||
// Sans ça, un panic Rust en WASM affiche juste "unreachable executed" — inutile.
|
||||
// `set_once()` garantit qu'on ne l'initialise pas plusieurs fois si hydrate() est appelé plusieurs fois.
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
// Monte l'application Leptos dans le <body> de la page HTML.
|
||||
//
|
||||
// En mode "hydration" (SSR + WASM), Leptos ne recrée pas le DOM depuis zéro.
|
||||
// Il trouve le HTML déjà rendu par le serveur et y attache les event listeners
|
||||
// pour rendre l'interface interactive. C'est plus rapide qu'un SPA classique
|
||||
// qui construit tout le DOM côté client.
|
||||
//
|
||||
// `hydrate_body` (Leptos 0.7) = mode SSR + hydration (≠ `mount_to_body` qui repart de zéro)
|
||||
leptos::mount::hydrate_body(App);
|
||||
}
|
||||
87
src/main.rs
87
src/main.rs
@@ -1,3 +1,86 @@
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
// main.rs — Point d'entrée du serveur Axum
|
||||
//
|
||||
// Ce fichier est compilé UNIQUEMENT en mode "ssr" (Server-Side Rendering).
|
||||
// `#[cfg(feature = "ssr")]` est l'équivalent d'un `#ifdef` en C :
|
||||
// le code qu'il protège n'existe pas dans le bundle WASM.
|
||||
//
|
||||
// Pour lancer le serveur :
|
||||
// cargo run --features ssr
|
||||
//
|
||||
// Pour lancer avec des logs détaillés :
|
||||
// RUST_LOG=debug cargo run --features ssr
|
||||
|
||||
#[cfg(feature = "ssr")]
|
||||
#[tokio::main]
|
||||
// `#[tokio::main]` est une macro qui transforme notre `fn main()` synchrone
|
||||
// en une fonction asynchrone, gérée par le runtime Tokio.
|
||||
// Sans ça, Rust ne saurait pas comment exécuter du code `async`.
|
||||
async fn main() {
|
||||
use axum::Router;
|
||||
use leptos::config::get_configuration;
|
||||
use leptos_axum::{generate_route_list, LeptosRoutes};
|
||||
use rust_ipam::{app::App, server::routes::not_found_handler};
|
||||
use tower_http::services::ServeDir;
|
||||
|
||||
// Initialise le système de logs structurés.
|
||||
// Les macros tracing::info!(), tracing::warn!(), tracing::error!()
|
||||
// n'affichent rien sans cet initialisateur.
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(
|
||||
// Lire le niveau de log depuis la variable d'environnement RUST_LOG,
|
||||
// ou utiliser "info" par défaut si elle n'est pas définie.
|
||||
// `unwrap_or_else` est une alternative idiomatique à `unwrap()` :
|
||||
// elle fournit une valeur de repli au lieu de paniquer.
|
||||
std::env::var("RUST_LOG").unwrap_or_else(|_| "info".to_string()),
|
||||
)
|
||||
.init();
|
||||
|
||||
tracing::info!("Démarrage du serveur Rust IPAM...");
|
||||
|
||||
// Charge la configuration Leptos.
|
||||
// Leptos peut lire un fichier `Leptos.toml` ou utiliser des valeurs par défaut.
|
||||
// On utilise `.expect()` car le serveur ne peut pas fonctionner sans configuration.
|
||||
// La chaîne passée à expect() est affichée si la valeur est Err ou None.
|
||||
// Note : get_configuration() est synchrone en Leptos 0.7 — pas de .await ici.
|
||||
let conf = get_configuration(None)
|
||||
.expect("Impossible de charger la configuration Leptos");
|
||||
let leptos_options = conf.leptos_options;
|
||||
let addr = leptos_options.site_addr;
|
||||
|
||||
// Analyse statiquement tous les composants `<Route>` dans `App`
|
||||
// pour construire la liste des URLs que Leptos doit gérer.
|
||||
let routes = generate_route_list(App);
|
||||
|
||||
// Construit le routeur Axum avec le pattern builder.
|
||||
// Chaque méthode retourne un nouveau Router modifié — c'est du chaînage fonctionnel.
|
||||
let app = Router::new()
|
||||
// Sert les fichiers statiques compilés par trunk (WASM, CSS, JS...).
|
||||
// `trunk build` les place dans `target/site/pkg/`.
|
||||
// Les navigateurs les demandent via des URLs comme `/pkg/rust-ipam.wasm`.
|
||||
.nest_service("/pkg", ServeDir::new("target/site/pkg"))
|
||||
// Branche toutes les routes Leptos dans Axum.
|
||||
// Pour chaque URL dans `routes`, Axum rend le composant App() en HTML.
|
||||
.leptos_routes(&leptos_options, routes, App)
|
||||
// Handler de repli : toute URL non reconnue retourne une 404.
|
||||
.fallback(not_found_handler)
|
||||
// Partage les options Leptos avec tous les handlers via le système d'état Axum.
|
||||
.with_state(leptos_options);
|
||||
|
||||
// Crée un listener TCP sur l'adresse configurée (par défaut 127.0.0.1:3000).
|
||||
let listener = tokio::net::TcpListener::bind(&addr)
|
||||
.await
|
||||
.expect(&format!("Impossible d'écouter sur l'adresse {}", addr));
|
||||
|
||||
tracing::info!("Serveur disponible sur http://{}", addr);
|
||||
|
||||
// Lance le serveur. Cette ligne bloque jusqu'à un Ctrl+C.
|
||||
axum::serve(listener, app)
|
||||
.await
|
||||
.expect("Erreur critique du serveur");
|
||||
}
|
||||
|
||||
// Ce bloc vide est nécessaire pour que le compilateur trouve un `fn main()`
|
||||
// quand on compile en mode WASM (où la feature "ssr" n'est pas activée).
|
||||
// En WASM, le vrai point d'entrée est la fonction `hydrate()` dans lib.rs.
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
fn main() {}
|
||||
|
||||
12
src/server/mod.rs
Normal file
12
src/server/mod.rs
Normal file
@@ -0,0 +1,12 @@
|
||||
// server/mod.rs — Module serveur
|
||||
//
|
||||
// Contient tout le code qui s'exécute uniquement côté serveur :
|
||||
// - Handlers HTTP additionnels (routes.rs)
|
||||
// - Fonctions serveur Leptos : accès à la base de données, authentification...
|
||||
// - Logique métier qui ne doit JAMAIS être exposée dans le bundle WASM
|
||||
//
|
||||
// Les "server functions" Leptos (marquées #[server]) sont déclarées ici.
|
||||
// Elles apparaissent comme des appels asynchrones normaux côté client,
|
||||
// mais s'exécutent exclusivement sur le serveur — transparence totale.
|
||||
|
||||
pub mod routes;
|
||||
26
src/server/routes.rs
Normal file
26
src/server/routes.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
// server/routes.rs — Handlers HTTP Axum additionnels
|
||||
//
|
||||
// Ces handlers complètent les routes gérées par Leptos.
|
||||
// Exemples d'usages futurs :
|
||||
// - Endpoints API REST (/api/...)
|
||||
// - Exports de fichiers (CSV, PDF...)
|
||||
// - Webhooks entrants
|
||||
// - Health check pour le monitoring (/health)
|
||||
//
|
||||
// `#[cfg(feature = "ssr")]` protège tout ce fichier :
|
||||
// Axum n'existe pas dans le bundle WASM, donc on ne compile ce code qu'en mode serveur.
|
||||
|
||||
#[cfg(feature = "ssr")]
|
||||
use axum::{http::StatusCode, response::IntoResponse};
|
||||
|
||||
// Handler 404 — utilisé comme fallback dans main.rs pour toute URL non reconnue.
|
||||
//
|
||||
// `impl IntoResponse` : Axum accepte n'importe quel type qui implémente ce trait.
|
||||
// Un tuple `(StatusCode, &str)` l'implémente automatiquement :
|
||||
// Axum en fait une réponse HTTP 404 avec le corps "Page introuvable".
|
||||
//
|
||||
// `async fn` est obligatoire pour les handlers Axum, même sans opération asynchrone.
|
||||
#[cfg(feature = "ssr")]
|
||||
pub async fn not_found_handler() -> impl IntoResponse {
|
||||
(StatusCode::NOT_FOUND, "Page introuvable")
|
||||
}
|
||||
Reference in New Issue
Block a user