Communitygithub.com

ajelinek/skills-stash

Utilisez cette compétence pour écrire ou refactoriser du code TypeScript Astro : Astro pour les pages statiques et les mises en page, SolidJS ou React pour toute interactivité, modules CSS dans des fichiers séparés, directives d'hydratation, collections de contenu, îles serveur, rendu à la demande, Actions Astro et HTML sémantique accessible.

Qu'est-ce que skills-stash ?

Cette compétence pour agents IA définit une architecture stricte pour les projets Astro, avec une séparation claire entre les composants statiques (pages, mises en page) et les composants interactifs (îles SolidJS/React). Elle impose l'utilisation exclusive de modules CSS dans des fichiers séparés (`styles.module.css`), jamais de styles en ligne ou dans les balises `<style>` d'Astro. La compétence couvre également les collections de contenu (Astro 5), les îles serveur (`server:defer`), le rendu à la demande (SSR), les middlewares et les Actions Astro. Elle est conçue pour être utilisée avec `ui-engineering` lors de tâches impliquant des décisions d'interface utilisateur partagées, de structure, de style, d'accessibilité ou de composants fondamentaux.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/ajelinek/skills-stash/tree/HEAD/astro.js

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Astro

Astro gère la structure statique : pages, mises en page et zones purement présentatives. SolidJS ou React gère toute l'interactivité : chaque composant qui gère une saisie utilisateur, gère un état ou répond à des événements est une île de framework — pas un fichier .astro.

Les modules CSS sont utilisés pour le style de tous les composants — toujours dans un fichier styles.module.css séparé, jamais en ligne ni à l'intérieur de la balise <style> d'Astro.

Quand utiliser cette compétence

  • Structurer un nouveau projet Astro ou ajouter des pages et zones de mise en page
  • Créer des pages .astro, mises en page ou zones statiques présentatives
  • Décider si quelque chose appartient à Astro ou à une île SolidJS/React
  • Choisir la directive d'hydratation à utiliser pour une île
  • Appliquer le style des modules CSS dans les fichiers .astro ou les îles de framework
  • Travailler avec des collections de contenu (src/content/, src/content.config.ts)
  • Intégrer les données de la couche service dans les pages Astro rendues côté serveur
  • Utiliser les îles serveur (server:defer) pour des zones différées personnalisées
  • Mettre en place le rendu à la demande (SSR) avec des adaptateurs et des middlewares
  • Définir et appeler des Actions Astro pour des mutations serveur typées

Astro vs Îles — La Décision d'Architecture Centrale

C'est la décision la plus importante dans tout projet Astro.

Ce qu'il faitUtiliser
Rend du HTML statique à partir de données — aucune interaction utilisateur.astro
Coquille de page, wrapper de mise en page, structure de navigation.astro
Sections de contenu, articles de blog, zones marketing.astro
Tout composant avec onClick, onChange, état de formulaire ou données réactivesÎle SolidJS ou React
Composants d'interface utilisateur fondamentaux (Bouton, Champ de saisie, Modale, Alerte, etc.)Île SolidJS ou React
Tout composant qui lit ou écrit dans un store ou un hook de serviceÎle SolidJS ou React

La règle en termes simples :

  • Astro rend la structure et le contenu. Il ne gère pas les interactions utilisateur.
  • SolidJS ou React gère toute l'interactivité, tout l'état des formulaires et tous les composants d'interface utilisateur interactifs fondamentaux — même un simple bouton qui déclenche un événement.
  • Ne créez pas d'interface utilisateur interactive dans les fichiers .astro. Astro n'a pas de réactivité. Tenter d'ajouter de l'interactivité à un fichier .astro produit un code fragile et non testable.

Quel framework — SolidJS ou React ?

Le projet en utilise un de manière cohérente. Vérifiez astro.config.mjs pour l'intégration configurée (@astrojs/solid-js ou @astrojs/react) et utilisez ce framework pour toutes les îles du projet. Ne mélangez pas les deux frameworks dans le même projet.

Lisez ./references/islands-and-hydration.md pour le guide de décision complet et la référence des directives d'hydratation.

Règles de Style — Modules CSS dans des Fichiers Séparés

C'est la règle la plus critique de cette compétence.

Chaque composant, page et mise en page Astro utilise des modules CSS pour le style limité. Le CSS vit dans un fichier séparé — jamais à l'intérieur de la balise <style> d'Astro.

NomDuComposant/
├── index.astro         ← logique et balisage du composant
└── styles.module.css   ← TOUT le style pour ce composant, toujours un fichier séparé
  • Toujours créer styles.module.css à côté de index.astro.
  • Jamais mettre de style à l'intérieur du bloc <style> d'Astro.
  • Jamais utiliser d'attributs style en ligne.
  • Importer le module en haut de la délimitation frontmatter : import styles from './styles.module.css'
  • Appliquer les classes avec la directive class:list ou la liaison de classe directe :
    • <div class={styles.container}>
    • <div class:list={[styles.container, isActive && styles.active]}>
  • Utiliser des noms de classe sémantiques. Pas d'empilement de classes utilitaires.
  • Utiliser des propriétés personnalisées CSS pour tous les tokens de design (couleurs, espacement, typographie).
  • Pas de !important. Pas de sélecteurs profonds. Pas de sélecteurs d'ID pour le style.

Lisez ./references/styling-and-css-modules.md pour la stratégie des tokens, les variables de thème, les règles responsives et les conseils d'animation. Lisez ./examples/button-component/ pour un exemple complet de Bouton avec un fichier CSS Module séparé.

Structure du Projet

src/
├── components/
│   ├── foundation/         # Primitives d'interface utilisateur interactives — SolidJS ou React, PAS .astro
│   │   ├── Button/
│   │   │   ├── index.tsx           ← SolidJS (.tsx) ou React (.tsx)
│   │   │   └── styles.module.css
│   │   └── Input/
│   │       ├── index.tsx
│   │       └── styles.module.css
│   ├── layout/             # Structure de mise en page statique — .astro
│   │   ├── Header/
│   │   │   ├── index.astro
│   │   │   └── styles.module.css
│   │   └── Footer/
│   │       ├── index.astro
│   │       └── styles.module.css
│   └── features/           # Zones fonctionnelles interactives — SolidJS ou React
│       └── SomeFeature/
│           ├── index.tsx           ← composant île
│           └── styles.module.css
├── layouts/
│   └── BaseLayout/
│       ├── index.astro             ← la coquille de mise en page est toujours .astro
│       └── styles.module.css
├── pages/
│   ├── index/
│   │   ├── index.astro             ← la page est toujours .astro
│   │   └── styles.module.css
│   └── [dynamic]/
│       ├── index.astro
│       └── styles.module.css
├── content/
│   ├── blog/
│   └── [nom-collection]/
├── content.config.ts   ← Schémas de collection et chargeurs Astro 5
├── store/
│   ├── repository/
│   ├── service/
│   └── config.ts
├── styles/
│   ├── tokens/
│   │   ├── _colors.css
│   │   ├── _spacing.css
│   │   └── _typography.css
│   ├── global.css
│   └── themes/
│       ├── light.css
│       └── dark.css
└── utils/

Conventions de nommage :

  • Pages et mises en page .astro : dossier PascalCase/ avec index.astro
  • Composants d'île de framework : dossier PascalCase/ avec index.tsx
  • Pages : dossier kebab-case/ avec index.astro ou [dynamic]/ avec index.astro
  • Fichiers de module CSS : toujours styles.module.css — un par dossier de composant
  • Utilitaires : kebab-case.ts

Lisez ./references/project-structure.md pour une ventilation complète des responsabilités des répertoires et des conventions de nommage.

Forme des Composants Astro

Les fichiers .astro sont uniquement pour la structure statique. Ils rendent du HTML à partir des propriétés et des données — ils ne gèrent pas d'événements ni d'état.

  • Utiliser des propriétés typées via interface Props dans la délimitation frontmatter.
  • Accéder aux propriétés avec Astro.props.
  • Garder les composants petits et à usage unique.
  • Préférer la composition au prop drilling.
  • Garder les expressions simples ; déplacer la logique complexe dans les variables frontmatter.
  • Utiliser des éléments HTML sémantiques — <section>, <article>, <nav>, <main>, <header> — au lieu de wrappers <div> génériques lorsque l'élément a une signification sémantique.
---
import styles from './styles.module.css'

interface Props {
  title: string
  subtitle?: string
}

const { title, subtitle } = Astro.props
---

<section class={styles.hero} aria-label={title}>
  <h1 class={styles.title}>{title}</h1>
  {subtitle && <p class={styles.subtitle}>{subtitle}</p>}
  <slot />
</section>

Lisez ./references/component-patterns.md pour les conventions frontmatter, l'utilisation des slots et la référence de l'API Astro.

Composants Fondamentaux — SolidJS ou React, Pas Astro

Les primitives d'interface utilisateur fondamentales (Bouton, Champ de saisie, Alerte, Modale, Sélecteur, Bascule, etc.) sont toujours construites comme des composants SolidJS ou React. Ils ne sont jamais des fichiers .astro.

Pourquoi : Les composants fondamentaux gèrent les événements utilisateur, gèrent le focus, exposent les callbacks onClick et onChange, et contiennent parfois un état interne. Rien de tout cela n'est possible dans un fichier .astro. Construire un "bouton" comme .astro produit un HTML statique qui ne peut pas répondre aux clics de manière typée et réutilisable.

La règle de décision :

  1. La primitive existe — l'utiliser.
  2. La primitive est proche mais une propriété manque — étendre la primitive existante.
  3. La primitive n'existe pas — la créer comme composant SolidJS ou React dans components/foundation/ avant de l'utiliser. Ne jamais intégrer des éléments interactifs ponctuels dans des composants de page ou de fonctionnalité.

Tous les composants fondamentaux doivent être cohérents, accessibles et fortement typés. Référez-vous à la compétence solid.js ou react pour les conventions d'implémentation qui s'appliquent à l'intérieur des composants d'île.

Îles et Hydratation

Chaque composant interactif est une île. Montez les îles à partir des pages et mises en page .astro en utilisant une directive client:*. Choisissez la directive minimale qui satisfait l'exigence d'interaction.

DirectiveQuand l'utiliser
client:loadDoit être interactif immédiatement au chargement de la page
client:idlePeut attendre que le navigateur soit inactif
client:visibleNécessite une hydratation uniquement lorsqu'il entre dans le viewport
client:media="(query)"Interactif uniquement à une taille de viewport spécifique
client:only="solid-js" ou client:only="react"Nécessite les API du navigateur au rendu ; ignorer le SSR

Par défaut, utilisez client:visible ou client:idle. Utilisez client:load uniquement pour l'interface utilisateur avec laquelle l'utilisateur interagira immédiatement — formulaires principaux, menus déroulants de navigation, pages d'authentification.

Les composants d'île ont toujours leur propre styles.module.css :

components/features/ContactForm/
├── index.tsx          ← Île SolidJS ou React
└── styles.module.css  ← module CSS séparé, même règle qu'ailleurs

Monter une île à partir d'une page Astro :

---
import styles from './styles.module.css'
import ContactForm from '../../components/features/ContactForm/index.tsx'

const { prefillEmail } = Astro.props
---

<section class={styles.section}>
  <h2 class={styles.heading}>Contactez-nous</h2>
  <ContactForm client:visible prefillEmail={prefillEmail} />
</section>

Lisez ./references/islands-and-hydration.md pour le guide de décision complet, les notes spécifiques au framework et les règles de passage de données.

Collections de Contenu

Les collections de contenu sont la manière canonique de gérer les fichiers Markdown, MDX et les données structurées avec une sécurité de type TypeScript complète.

Changements clés d'Astro 5 :

  • La configuration se trouve à src/content.config.ts (pas src/content/config.ts)
  • Les collections utilisent un loader — glob() ou file() depuis astro/loaders
  • render(entry) est une fonction importée depuis astro:content (pas entry.render())
  • Importer z depuis astro:content, pas directement de zod
// src/content.config.ts
import { defineCollection, z, reference } from 'astro:content'
import { glob } from 'astro/loaders'

const blog = defineCollection({
  loader: glob({ pattern: '**/*.md', base: './src/content/blog' }),
  schema: z.object({
    title: z.string(),
    pubDate: z.coerce.date(),
    draft: z.boolean().default(false),
  }),
})

export const collections = { blog }

Rendu dans une page :

---
import { getEntry, render } from 'astro:content'
const post = await getEntry('blog', Astro.params.slug)
const { Content } = await render(post)
---
<Content />

Lisez ./references/content-collections.md pour l'API complète : chargeurs, références inter-collections, chargeurs personnalisés, collections d'exécution et motifs de routes dynamiques.

Îles Serveur, SSR et Actions

Îles Serveur (server:defer)

Différez un composant .astro personnalisé ou dynamique tout en servant la coquille de la page immédiatement. Nécessite un adaptateur.

<UserCart server:defer>
  <span slot="fallback">···</span>
</UserCart>

Le composant différé s'exécute côté serveur et est diffusé en continu. Utilisez-le pour l'interface utilisateur spécifique à l'utilisateur (compteurs de panier, notifications, salutations personnalisées) qui bloquerait autrement la livraison de la page statique.

Rendu à la Demande (SSR)

Optez pour les pages de rendu serveur avec export const prerender = false (mode hybride) ou définissez output: 'server' globalement.

Les pages SSR ont accès à Astro.cookies, Astro.request, Astro.redirect(), et Astro.locals (rempli par le middleware).

Middleware

Définissez la logique d'interception des requêtes dans src/middleware.ts :

import { defineMiddleware } from 'astro:middleware'

export const onRequest = defineMiddleware(async (context, next) => {
  context.locals.user = await getUser(context.cookies.get('session')?.value)
  return next()
})

Actions Astro

Fonctions serveur typées définies dans src/actions/index.ts, appelables depuis les îles ou les formulaires HTML :

// src/actions/index.ts
import { defineAction, ActionError } from 'astro:actions'
import { z } from 'astro:content'

export const server = {
  newsletter: {
    subscribe: defineAction({
      input: z.object({ email: z.string().email() }),
      handler: async ({ email }) => {
        await addSubscriber(email)
        return { success: true }
      },
    }),
  },
}

Appel depuis une île :

import { actions } from 'astro:actions'
const { data, error } = await actions.newsletter.subscribe({ email })

Utilisez isInputError(error) pour distinguer les erreurs de validation Zod des erreurs de handler.

Lisez ./references/server-rendering.md pour une couverture complète : modes de rendu, configuration de l'adaptateur, middleware, îles serveur, API à la demande, actions avec formulaires, codes d'erreur, variables d'environnement typées (astro:env) et transitions de vue.

Référence de l'API Astro

  • Astro.props — propriétés typées du composant
  • Astro.params — paramètres de route dynamiques ([slug], [...path])
  • Astro.request — objet de requête côté serveur (en-têtes, cookies, URL)
  • Astro.url — URL de la page actuelle
  • getStaticPaths() — énumérer les chemins pour la génération de site statique
  • getEntry() / getCollection() — requêtes de collection de contenu

Flux de Données de la Couche Service

Les pages et mises en page Astro sont l'endroit approprié pour appeler les fonctions de service ou de référentiel dans la délimitation frontmatter. Les composants doivent recevoir les données sous forme de propriétés.

  • Récupérez les données dans le frontmatter de la page, pas à l'intérieur des composants.
  • Transmettez les données vers le bas sous forme de propriétés typées.
  • Les composants ne doivent pas appeler directement les référentiels ou les API externes.
  • Gardez la validation et la logique métier dans la couche service.

Accessibilité

  • Utilisez des éléments HTML sémantiques chaque fois que l'élément a une signification.
  • Ajoutez des attributs ARIA là où ils ajoutent des informations sémantiques réelles.
  • Assurez-vous que tous les éléments interactifs ont des noms accessibles.
  • Maintenez des états de focus visibles.
  • Gardez une taille de cible tactile minimale de 44px pour les éléments interactifs.
  • Respectez prefers-reduced-motion.
  • Structurez les titres logiquement (h1 → h2 → h3) dans le contenu de la page.

Lisez ./references/accessibility-patterns.md pour les modèles ARIA, les étiquettes de formulaire et les conseils de hiérarchie des titres.

Fichiers de Support

  • ./references/styling-and-css-modules.md Règles des modules CSS, stratégie des tokens, thèmes, règles responsives, animations, et conventions de nommage détaillées.

  • ./references/accessibility-patterns.md Modèles ARIA, structure de formulaire, hiérarchie des titres, navigation au clavier, et exigences de contraste des couleurs.

  • ./references/component-patterns.md Conventions des composants Astro : frontmatter, slots, variables de template, propriétés typées Astro.props, et directives de composition.

  • ./references/islands-and-hydration.md Directives d'hydratation complètes (client:load, client:idle, client:visible, client:media, client:only), transmission de données Astro → île, et conventions propres au framework islands.

  • ./references/server-rendering.md Guide complet du rendu serveur : modes de rendu d'Astro, configuration de l'adaptateur (Node, Deno, Cloudflare, Vercel, Netlify), middleware, Astro.locals, actions avec isInputError, codes d'erreur Astro, variables d'environnement typées (defineEnv / astro:env), îles serveur (server:defer), transitions de vue, et API de streaming.

  • ./references/content-collections.md API des collections Astro 5 : définitions de collections basées sur un chargeur, schémas (z.object, z.coerce.date), références inter-collections (reference()), chargeurs personnalisés, collections d'exécution (store.insert(), store.setCollectionData()), et motifs de routes dynamiques avec getStaticPaths().

  • ./references/project-structure.md Arborescence complète du projet et conventions de nommage : emplacements des dossiers, types de fichiers par répertoire (components/foundation/, components/layout/, components/features/), et lignes directrices pour l'organisation des pages et des mises en page.

Skills associés