Salut tout le monde. Aujourd'hui, on va voir comment lancer un projet Astro sans se prendre la tête. Astro, c'est un framework super efficace pour créer des sites web rapides. L'idée, c'est de faire du HTML/CSS boosté avec un peu de JavaScript, mais juste là où il faut.
On va partir de zéro dans le terminal et on finira par afficher une liste d'éléments dynamiquement. C'est parti.
Ouvrez votre terminal. Assurez-vous d'avoir Node.js installé, sinon ça ne marchera pas.
Tapez cette commande pour créer le projet :
npm create astro@latest
L'assistant va vous poser quelques questions :
./monsupersite).Une fois fini, entrez dans le dossier et lancez le serveur :
cd monsupersite
npm run dev
Ouvrez l'URL qui s'affiche (souvent http://localhost:4321) dans votre navigateur. Vous devriez voir la page d'accueil par défaut.
Ouvrez le projet dans votre éditeur de code (VS Code est top pour ça).
Allez voir dans le dossier src/pages. Vous y trouverez index.astro. C'est votre page d'accueil.
Un fichier .astro est divisé en deux parties :
---. C'est ici qu'on écrit le JavaScript qui s'exécute au moment de la construction de la page.On va modifier src/pages/index.astro. Supprimez tout le contenu et mettez ça pour tester :
---
import Layout from "../layouts/Layout.astro";
const nom = "Alexis";
---
<Layout>
<h1>Salut {nom}</h1>
</Layout>
Sauvegardez. Votre navigateur devrait afficher "Salut Alexis". Les accolades {} servent à afficher la valeur d'une variable JavaScript dans le HTML.
Attention, le code dans les tirets --- s'execute côté serveur, pas dans le navigateur. Il n'est pas possible d'utiliser des fonctionnalités spécifiques au navigateur ici, ou de modifier le DOM (contenu de la page) directement.
On peut aussi faire des conditions. Par exemple, on va afficher un message différent selon si les secondes sont paires ou impaires.
---
const date = new Date();
const secondes = date.getSeconds();
---
<html>
<body>
<h1>Les secondes sont {secondes}</h1>
{secondes % 2 === 0 ? (
<p>Les secondes sont paires !</p>
) : (
<p>Les secondes sont impaires !</p>
)}
</body>
</html>
Pour ceux qui on déjà fait du JavaScript ou du C, le ? et le : fonctionnent comme un if et un else. Si la condition avant le ? est vraie, on affiche ce qu'il y a après le ?, sinon on affiche ce qu'il y a après le :. Pour ne pas se perdre, on peut aussi utiliser des parenthèses () pour bien délimiter les blocs.
Testez ça en sauvegardant le fichier. Rafraîchissez la page plusieurs fois pour voir le message changer selon les secondes.
Maintenant, on va transpiler le code du projet en un site classique. Vous pouvez arrêter le serveur de développement avec CTRL+C dans le terminal, puis taper :
npm run build
npm run preview
Cela va générer le site dans le dossier dist et lancer un serveur pour le prévisualiser. Ouvrez l'URL indiquée (souvent http://localhost:4321) pour voir votre site compilé.
Si vous revenez dans votre navigateur, vous verrez que tout fonctionne pareil, mais cette fois le site est statique et optimisé... un peu trop statique même... car les secondes ne changent plus ! C'est normal, pendant le développement le site est généré à la volée à chaque requête, mais une fois compilé, le contenu est figé pour pouvoir être servi rapidement par un serveur web comme nginx qui ne sait pas exécuter du JavaScript côté serveur.
Il faut donc faire attention à ce qu'on utilise dans le Frontmatter. Si on a besoin de faire des choses dynamiques côté client (dans le navigateur), il faudra utiliser du JavaScript classique ou des composants interactifs (React, Svelte, etc.) que l'on intégrera dans Astro.
Les composants interactifs sont intégrables dans Astro très facilement, mais cela sort du cadre de ce tutoriel, pour les plus audacieux, vous pouvez jeter un œil à la documentation officielle.
Pour la suite, vous pouvez continuer à utiliser npm run dev.
Maintenant, imaginons qu'on a une liste de trucs à afficher, comme des membres d'une équipe ou des articles. On ne va pas copier-coller le HTML dix fois, surtout si on change d'équipe tous les ans (comme cet exemple). On va utiliser une boucle.
Dans Astro (comme en React), on utilise la fonction .map() sur les tableaux pour générer du HTML.
Modifiez votre index.astro comme ceci :
---
import Layout from "../layouts/Layout.astro";
// On définit notre liste de données ici
const membres = [
"Alice",
"Bob",
"Charlie",
"David"
];
---
<Layout>
<h1>L'équipe</h1>
<ul>
{membres.map((membre) => (
<li>{membre}</li>
))}
</ul>
</Layout>
Ce qu'il se passe ici :
---, on crée un tableau membres.{} pour dire à Astro "Attention, je vais faire du code".membres et on le "map". Pour chaque membre trouvé dans la liste, on renvoie une balise <li> contenant le nom.Si vous regardez votre page, vous avez maintenant une liste générée automatiquement. Si vous ajoutez un nom dans le tableau, il apparaîtra tout seul dans la liste.
On peut aussi avoir des objets plus complexes. Par exemple, chaque membre peut avoir un nom et un rôle, comme ceci :
---
import Layout from "../layouts/Layout.astro";
const membres = [
{ nom: "Alice", role: "Cheffe de projet" },
{ nom: "Bob", role: "Designer" },
{ nom: "Charlie", role: "Développeuse" },
{ nom: "David", role: "Testeur" }
];
---
<Layout>
<h1>L'équipe</h1>
<ul>
{membres.map((membre) => (
<li><h2>{membre.nom}</h2> - <h3>{membre.role}</h3></li>
))}
</ul>
</Layout>
Ici, même si on ne répète pas le HTML, on a une structure plus complexe pour ajouter chaque membre avec son rôle. Pour éviter trop de complexité imbriquée dans le même fichier, on peut créer un composant Astro séparé pour un membre, et l'importer dans la page principale :
src/components/Membre.astro avec ce contenu :---
const { nom, role } = Astro.props;
---
<div class="membre">
<h2>{nom}</h2>
<h3>{role}</h3>
</div>
<style>
.membre {
border: 1px solid #ccc;
padding: 10px;
margin: 5px 0;
border-radius: 5px;
}
.membre h2 {
margin: 0;
}
.membre h3 {
margin: 0;
color: #666;
}
</style>
src/pages/index.astro pour utiliser ce composant :---
import Layout from "../layouts/Layout.astro";
import Membre from "../components/Membre.astro"; // on importe le composant
const membres = [
{ nom: "Alice", role: "Cheffe de projet" },
{ nom: "Bob", role: "Designer" },
{ nom: "Charlie", role: "Développeuse" },
{ nom: "David", role: "Testeur" }
];
---
<Layout>
<h1>L'équipe</h1>
<div>
{membres.map((membre) => (
<Membre nom={membre.nom} role={membre.role} />
))}
</div>
</Layout>
<style>
.equipe {
display: flex;
flex-direction: row;
width: max-content;
gap: 20px;
}
</style>
Ici, on crée un composant Membre qui prend des propriétés nom et role. Dans la page principale, on utilise ce composant dans la boucle pour chaque membre. Pour ajouter du CSS spécifique au composant, on l'a mis dans le composant lui-même, ce qui permet de garder le style encapsulé, alors qu'on aurait dû l'ajouter dans la page si on avait gardé tout le HTML dans index.astro.
Vous aurez peut-être remarqué en tapant le code qu'il n'y avait pas d'autocomplétion pour les propriétés nom et role dans le composant Membre.astro. Pour améliorer ça, on peut définir un type pour les propriétés attendues. Voici comment faire :
---
interface Props {
nom: string;
role: string;
}
const { nom, role }: Props = Astro.props;
---
<div class="membre">
<h2>{nom}</h2>
<h3>{role}</h3>
</div>
<style>
.membre {
border: 1px solid #ccc;
padding: 10px;
margin: 5px 0;
border-radius: 5px;
}
.membre h2 {
margin: 0;
}
.membre h3 {
margin: 0;
color: #666;
}
</style>
Pour des composants plus flexibles, il est parfois utile d'utiliser des slots pour pouvoir insérer d'autres composants dans un composant parent. Par exemple, on peut créer un bouton qui ouvre une pop-up avec du contenu personnalisé. Créez un fichier src/components/ButtonPopup.astro avec ce contenu :
---
interface Props {
titre: string;
boutonTexte: string;
}
const { titre, boutonTexte } = Astro.props;
const idPopup = "popup-" + Math.random().toString(36).substring(2, 15); // ID unique pour chaque pop-up
---
<button id={"btn-" + idPopup}>{boutonTexte}</button> <!-- on peut faire des opérations dans les {} -->
<div id={idPopup} class="popup" data-open="false">
<div class="top">
<h2 id={"title-" + idPopup}>{titre}</h2>
<button id={"close-" + idPopup}>Fermer</button>
</div>
<slot /> <!-- le contenu personnalisé s'insère ici -->
</div>
<style>
.top {
display: flex;
justify-content: space-between;
align-items: center;
}
div.popup {
border: 1px solid #ccc;
padding: 10px;
border-radius: 5px;
display: none;
position: fixed;
width: 300px;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
div.popup[data-open="true"] {
background-color: #f9f9f9;
display: block;
}
button {
padding: 10px 15px;
border: none;
border-radius: 5px;
cursor: pointer;
}
button:hover {
background-color: #0056b3;
}
</style>
<script define:vars={{ idPopup }}>
// On passe l'idPopup du serveur au client pour faire le lien entre le bouton et la pop-up
const btn = document.getElementById("btn-" + idPopup);
const popup = document.getElementById(idPopup);
const closeBtn = document.getElementById("close-" + idPopup);
if (!btn || !popup || !closeBtn) return;
btn.addEventListener("click", () => {
popup.setAttribute("data-open", "true");
});
closeBtn.addEventListener("click", () => {
popup.setAttribute("data-open", "false");
});
</script>
Une fois le composant créé, on peut l'ajouter aux membres dans src/components/Membre.astro comme ceci :
---
import ButtonPopup from "./ButtonPopup.astro";
const { nom, role } = Astro.props;
---
<div class="membre">
<h2>{nom}</h2>
<h3>{role}</h3>
<ButtonPopup titre={"Plus d'infos sur " + nom} boutonTexte="En savoir plus">
<h4>Rôle :</h4>
<p>{role}</p>
</ButtonPopup>
</div>
<style> ... </style>
Les popups fonctionneront pour chaque membre, avec un contenu personnalisé à l'intérieur grâce au slot.
Pour aller un peu plus loin, on peut aussi insérer plusieurs slots dans un composant en les nommant. Par exemple, on peut modifier ButtonPopup.astro pour avoir un slot pour le contenu principal et un autre pour le pied de page :
---
interface Props {
boutonTexte: string;
}
const { boutonTexte } = Astro.props;
const idPopup = "popup-" + Math.random().toString(36).substring(2, 15); // ID unique pour chaque pop-up
---
<button id={"btn-" + idPopup}>{boutonTexte}</button> <!-- on peut faire des opérations dans les {} -->
<div id={idPopup} class="popup" data-open="false">
<div class="top">
<h2 id={"title-" + idPopup}><slot name="title">Popup</slot></h2>
<button id={"close-" + idPopup}>Fermer</button>
</div>
<slot /> <!-- le contenu personnalisé s'insère ici -->
<div class="footer">
<slot name="footer"></slot>
</div>
</div>
...
Ainsi dans les pages ou composants qui utilisent ButtonPopup, on peut spécifier quel contenu va dans chaque slot (notez que le slot par défaut n'a pas de nom) :
<ButtonPopup boutonTexte="Ouvrir la pop-up">
<h4 slot="title">Titre personnalisé</h4>
<p>Contenu principal de la pop-up.</p>
<div slot="footer">
<button>Action dans le footer</button>
</div>
</ButtonPopup>
Astro crée des routes automatiquement à partir de l'arborescence src/pages. Pour ajouter ou changer une page :
.astro dans src/pages. Le chemin devient l'URL.
src/pages/about.astro → /aboutsrc/pages/index.astro → /src/pages/docs/getting-started.astro → /docs/getting-startedExemple simple pour src/pages/about.astro :
---
const titre = "À propos";
---
<html>
<body>
<h1>{titre}</h1>
<p>Contenu de la page about.</p>
<a href="/">Retour à l'accueil</a>
</body>
</html>
Pages index dans un dossier :
src/pages/blog/index.astro → /blogRoutes dynamiques (paramètres) :
src/pages/blog/[slug].astro. Vous récupérez la valeur via Astro.params.slug dans le frontmatter.getStaticPaths() pour définir les valeurs possibles pour slug (ou un autre paramètre de votre choix). Rappelez-vous que Astro compile des sites statiques, donc toutes les routes dynamiques doivent être connues à l'avance.Exemple minimal :
---
const { slug } = Astro.params;
export async function getStaticPaths() {
return [
{ params: { slug: 'chemin1' } },
{ params: { slug: 'chemin2' } },
];
}
---
<h1>Article: {slug}</h1>
Liens et navigation :
<a href="/chemin"> pour naviguer.Bonnes pratiques :
npm run dev puis après npm run build / npm run preview pour vérifier le comportement en production.C'est tout ce qu'il faut pour ajouter ou changer des pages dans un site Astro.
Maintenant que vous avez les bases d'Astro, vous pouvez explorer plus loin en améliorant le style des pages avec du CSS, en ajoutant des composants plus interactifs avec des frameworks comme React, ou Svelte, Vue. N'hésitez pas à consulter la documentation officielle d'Astro pour découvrir toutes les fonctionnalités avancées et les intégrations possibles.
Astro permet aussi de générer des pages à partir de documents Markdown, pour écrire facilement des blogs ou des documentations.