Communitygithub.com

ajelinek/skills-stash

Usa esta habilidad al escribir o refactorizar código Astro TypeScript: Astro para páginas y diseños estáticos, islas SolidJS o React para toda la interactividad, Módulos CSS en archivos separados, directivas de hidratación, colecciones de contenido, islas de servidor, renderizado bajo demanda, Acciones de Astro y HTML semántico accesible. Úsala junto con `ui-engineering` cuando la tarea también involucre estructura de UI compartida, estilos, semántica, accesibilidad o decisiones sobre componentes fundamentales. Actívala al recibir solicitudes para construir una página, diseño, isla, acción o característica renderizada en servidor con Astro.

¿Qué es skills-stash?

Esta habilidad, `ajelinek/skills-stash`, proporciona una guía completa para desarrollar aplicaciones web con Astro, centrándose en una arquitectura clara que separa la estructura estática de la interactividad. Define que Astro se encarga de páginas, diseños y regiones puramente estáticas, mientras que toda la interactividad (manejo de eventos, estado del usuario) debe implementarse en islas de SolidJS o React, nunca en archivos `.astro`. Una regla fundamental es el uso obligatorio de Módulos CSS en archivos separados (`styles.module.css`), prohibiendo estilos en línea o dentro de las etiquetas `<style>` de Astro, lo que garantiza estilos modulares y mantenibles. La habilidad cubre la estructura de proyectos, convenciones de nomenclatura, hidratación de islas con directivas `client:*`, colecciones de contenido con el nuevo formato de Astro 5, islas de servidor (`server:defer`), renderizado bajo demanda (SSR), middleware y Acciones de Astro para mutaciones seguras de servidor. El objetivo es que los desarrolladores sigan una arquitectura predecible y escalable, evitando errores comunes como poner interactividad en Astro o mezclar estilos, y promoviendo componentes accesibles y con tipos fuertes.

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

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Astro

Astro es dueño de la estructura estática: páginas, diseños y regiones puramente presentacionales. SolidJS o React son dueños de toda la interactividad: cada componente que maneja entrada del usuario, administra estado o responde a eventos es una isla de framework, no un archivo .astro.

Los Módulos CSS se utilizan para todos los estilos de componentes, siempre en un archivo separado styles.module.css, nunca en línea ni dentro del bloque <style> de Astro.

Cuándo Usar Esta Habilidad

  • Estructurar un nuevo proyecto Astro o agregar páginas y áreas de diseño
  • Construir páginas .astro, diseños o regiones presentacionales estáticas
  • Decidir si algo pertenece a Astro o a una isla de SolidJS/React
  • Elegir qué directiva de hidratación usar para una isla
  • Aplicar estilos con Módulos CSS dentro de archivos .astro o islas de framework
  • Trabajar con colecciones de contenido (src/content/, src/content.config.ts)
  • Conectar datos de la capa de servicios en páginas Astro renderizadas en servidor
  • Usar islas de servidor (server:defer) para regiones personalizadas diferidas
  • Configurar renderizado bajo demanda (SSR) con adaptadores y middleware
  • Definir y llamar Acciones de Astro para mutaciones seguras de servidor

Astro vs Islas — La Decisión Arquitectónica Central

Esta es la decisión más importante en cualquier proyecto Astro.

Qué haceUsa
Renderiza HTML estático a partir de datos — sin interacción del usuario.astro
Esqueleto de página, envoltorio de diseño, estructura de navegación.astro
Secciones de contenido, publicaciones de blog, regiones de marketing.astro
Cualquier componente con onClick, onChange, estado de formulario o datos reactivosIsla SolidJS o React
Componentes de UI fundamentales (Button, Input, Modal, Alert, etc.)Isla SolidJS o React
Cualquier componente que lea o escriba en un store o hook de servicioIsla SolidJS o React

La regla en términos simples:

  • Astro renderiza estructura y contenido. No maneja interacción del usuario.
  • SolidJS o React maneja toda la interactividad, todo el estado de formularios y todos los primitivos de UI interactivos fundamentales, incluso un simple botón que dispara un evento.
  • No construyas UI interactiva en archivos .astro. Astro no tiene reactividad. Intentar agregar interactividad a un archivo .astro produce código frágil y no comprobable.

¿Qué framework — SolidJS o React?

El proyecto usa uno de manera consistente. Revisa astro.config.mjs para la integración configurada (@astrojs/solid-js o @astrojs/react) y usa ese framework para todas las islas del proyecto. No mezcles ambos frameworks en el mismo proyecto.

Lee ./references/islands-and-hydration.md para la guía de decisión completa y la referencia de directivas de hidratación.

Reglas de Estilo — Módulos CSS en Archivos Separados

Esta es la regla más crítica de esta habilidad.

Cada componente, página y diseño de Astro usa Módulos CSS para estilos con ámbito. El CSS vive en un archivo separado, nunca dentro de la etiqueta <style> de Astro.

ComponentName/
├── index.astro         ← lógica del componente y marcado
└── styles.module.css   ← TODOS los estilos para este componente, siempre un archivo separado
  • Siempre crea styles.module.css junto a index.astro.
  • Nunca pongas estilos dentro del bloque <style> de Astro.
  • Nunca uses atributos style en línea.
  • Importa el módulo al principio de la valla de frontmatter: import styles from './styles.module.css'
  • Aplica clases usando la directiva class:list o enlace directo de clase:
    • <div class={styles.container}>
    • <div class:list={[styles.container, isActive && styles.active]}>
  • Usa nombres de clase semánticos. Sin apilamiento de clases utilitarias.
  • Usa propiedades personalizadas CSS para todos los tokens de diseño (colores, espaciado, tipografía).
  • Sin !important. Sin selectores profundos. Sin selectores de ID para estilos.

Lee ./references/styling-and-css-modules.md para la estrategia de tokens, variables de tema, reglas responsivas y guía de animaciones. Lee ./examples/button-component/ para un ejemplo completo de Button con archivo CSS Module separado.

Estructura del Proyecto

src/
├── components/
│   ├── foundation/         # Primitivos de UI interactivos — SolidJS o React, NO .astro
│   │   ├── Button/
│   │   │   ├── index.tsx           ← SolidJS (.tsx) o React (.tsx)
│   │   │   └── styles.module.css
│   │   └── Input/
│   │       ├── index.tsx
│   │       └── styles.module.css
│   ├── layout/             # Estructura de diseño estático — .astro
│   │   ├── Header/
│   │   │   ├── index.astro
│   │   │   └── styles.module.css
│   │   └── Footer/
│   │       ├── index.astro
│   │       └── styles.module.css
│   └── features/           # Áreas de características interactivas — SolidJS o React
│       └── SomeFeature/
│           ├── index.tsx           ← componente isla
│           └── styles.module.css
├── layouts/
│   └── BaseLayout/
│       ├── index.astro             ← el esqueleto del diseño siempre es .astro
│       └── styles.module.css
├── pages/
│   ├── index/
│   │   ├── index.astro             ← la página siempre es .astro
│   │   └── styles.module.css
│   └── [dynamic]/
│       ├── index.astro
│       └── styles.module.css
├── content/
│   ├── blog/
│   └── [collection-name]/
├── content.config.ts   ← Esquemas y cargadores de colecciones de Astro 5
├── store/
│   ├── repository/
│   ├── service/
│   └── config.ts
├── styles/
│   ├── tokens/
│   │   ├── _colors.css
│   │   ├── _spacing.css
│   │   └── _typography.css
│   ├── global.css
│   └── themes/
│       ├── light.css
│       └── dark.css
└── utils/

Convenciones de nomenclatura:

  • Páginas y diseños .astro: carpeta PascalCase/ con index.astro
  • Componentes de isla de framework: carpeta PascalCase/ con index.tsx
  • Páginas: carpeta kebab-case/ con index.astro o [dynamic]/ con index.astro
  • Archivos CSS Module: siempre styles.module.css — uno por directorio de componente
  • Utilidades: kebab-case.ts

Lee ./references/project-structure.md para un desglose completo de las responsabilidades de los directorios y las convenciones de nomenclatura.

Forma del Componente Astro

Los archivos .astro son solo para estructura estática. Renderizan HTML a partir de props y datos — no manejan eventos ni administran estado.

  • Usa props tipificadas mediante interface Props en la valla de frontmatter.
  • Accede a props con Astro.props.
  • Mantén los componentes pequeños y de un solo propósito.
  • Prefiere composición sobre perforación de props.
  • Mantén las expresiones simples; mueve la lógica compleja a variables de frontmatter.
  • Usa elementos HTML semánticos — <section>, <article>, <nav>, <main>, <header> — en lugar de envoltorios <div> genéricos cuando el elemento tenga significado semántico.
---
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>

Lee ./references/component-patterns.md para convenciones de frontmatter, uso de slots y referencia de la API de Astro.

Componentes Fundamentales — SolidJS o React, No Astro

Los primitivos de UI fundamentales (Button, Input, Alert, Modal, Select, Toggle, etc.) siempre se construyen como componentes SolidJS o React. Nunca son archivos .astro.

Por qué: Los componentes fundamentales manejan eventos del usuario, administran el foco, exponen callbacks onClick y onChange, y a veces tienen estado interno. Nada de esto es posible en un archivo .astro. Construir un "botón" como .astro produce HTML estático que no puede responder a clics de manera tipificada y reutilizable.

La regla de decisión:

  1. El primitivo existe — úsalo.
  2. El primitivo está cerca pero le falta una prop — extiende el primitivo existente.
  3. El primitivo no existe — créalo como un componente SolidJS o React en components/foundation/ antes de usarlo. Nunca coloques elementos interactivos únicos en componentes de página o característica.

Todos los componentes fundamentales deben ser consistentes, accesibles y fuertemente tipificados. Consulta la habilidad solid.js o react para las convenciones de implementación que se aplican dentro de los componentes isla.

Islas e Hidratación

Cada componente interactivo es una isla. Monta islas desde páginas y diseños .astro usando una directiva client:*. Elige la directiva mínima que satisfaga el requisito de interacción.

DirectivaCuándo usarla
client:loadDebe ser interactivo inmediatamente al cargar la página
client:idlePuede esperar hasta que el navegador esté inactivo
client:visibleSolo necesita hidratarse cuando entra en el viewport
client:media="(query)"Solo es interactivo en un tamaño de viewport específico
client:only="solid-js" o client:only="react"Requiere APIs del navegador en el renderizado; omite SSR

Por defecto, usa client:visible o client:idle. Usa client:load solo para UI con la que el usuario interactuará inmediatamente — formularios principales, desplegables de navegación, páginas de autenticación.

Los componentes isla siempre tienen su propio styles.module.css:

components/features/ContactForm/
├── index.tsx          ← Isla SolidJS o React
└── styles.module.css  ← CSS Module separado, misma regla que en todos lados

Montar una isla desde una página 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}>Contáctanos</h2>
  <ContactForm client:visible prefillEmail={prefillEmail} />
</section>

Lee ./references/islands-and-hydration.md para la guía de decisión completa, notas específicas del framework y reglas de paso de datos.

Colecciones de Contenido

Las colecciones de contenido son la forma canónica de gestionar archivos Markdown, MDX y datos estructurados con seguridad de tipos TypeScript completa.

Cambios clave en Astro 5:

  • La configuración está en src/content.config.ts (no src/content/config.ts)
  • Las colecciones usan un loader — glob() o file() desde astro/loaders
  • render(entry) es una función importada de astro:content (no entry.render())
  • Importa z de astro:content, no directamente 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 }

Renderizar en una página:

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

Lee ./references/content-collections.md para la API completa: cargadores, referencias entre colecciones, cargadores personalizados, colecciones en tiempo de ejecución y patrones de ruta dinámica.

Islas de Servidor, SSR y Acciones

Islas de Servidor (server:defer)

Difiere un componente .astro personalizado o dinámico mientras se sirve el esqueleto de la página inmediatamente. Requiere un adaptador.

<Observa que no se traduce la prop server:defer ya que es código>
<UserCart server:defer>
  <span slot="fallback">···</span>
</UserCart>

El componente diferido se ejecuta del lado del servidor y se transmite. Úsalo para UI específica del usuario (contadores de carrito, notificaciones, saludos personalizados) que de otro modo bloquearían la entrega de la página estática.

Renderizado Bajo Demanda (SSR)

Opta por páginas en renderizado de servidor con export const prerender = false (modo híbrido) o configura output: 'server' globalmente.

Las páginas SSR tienen acceso a Astro.cookies, Astro.request, Astro.redirect() y Astro.locals (poblado por middleware).

Middleware

Define lógica de interceptación de solicitudes en 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()
})

Acciones de Astro

Funciones de servidor seguras de tipos definidas en src/actions/index.ts, invocables desde islas o formularios 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 }
      },
    }),
  },
}

Llamar desde una isla:

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

Usa isInputError(error) para distinguir errores de validación Zod de errores del handler.

Lee ./references/server-rendering.md para cobertura completa: modos de renderizado, configuración de adaptador, middleware, islas de servidor, APIs bajo demanda, acciones con formularios, códigos de error, variables de entorno tipificadas (astro:env) y transiciones de vista.

Referencia de la API de Astro

  • Astro.props — props tipificadas del componente
  • Astro.params — parámetros de ruta dinámica ([slug], [...path])
  • Astro.request — objeto de solicitud del lado del servidor (encabezados, cookies, URL)
  • Astro.url — URL de la página actual
  • getStaticPaths() — enumera rutas para la generación de sitios estáticos
  • getEntry() / getCollection() — consultas de colecciones de contenido

Flujo de Datos de la Capa de Servicios

Las páginas y diseños de Astro son el lugar correcto para llamar funciones de servicio o repositorio en la valla de frontmatter. Los componentes deben recibir datos como props.

  • Obtén datos en el frontmatter de la página, no dentro de los componentes.
  • Pasa datos hacia abajo como props tipificadas.
  • Los componentes no deben llamar repositorios o APIs externas directamente.
  • Mantén la validación y la lógica de negocio en la capa de servicios.

Accesibilidad

  • Usa elementos HTML semánticos donde el elemento tenga significado.
  • Agrega atributos ARIA donde agreguen información semántica real.
  • Asegúrate de que todos los elementos interactivos tengan nombres accesibles.
  • Mantén estados de foco visibles.
  • Mantén un tamaño mínimo de objetivo táctil de 44px para elementos interactivos.
  • Respeta prefers-reduced-motion.
  • Estructura los encabezados de manera lógica (h1 → h2 → h3) dentro del contenido de la página.

Lee ./references/accessibility-patterns.md para patrones ARIA, etiquetas de formularios y guía de jerarquía de encabezados.

Archivos de Soporte

  • ./references/styling-and-css-modules.md — Reglas de Módulos CSS, tokens, variables de tema
  • ./references/islands-and-hydration.md — Guía de decisión de hidratación, notas específicas del framework
  • ./references/server-rendering.md — SSR, middleware, islas de servidor, acciones, transiciones de vista
  • ./references/component-patterns.md — Convenciones de frontmatter, slots, API de Astro
  • ./references/project-structure.md — Desglose de directorios, nomenclatura
  • ./references/content-collections.md — API de colecciones, cargadores, esquemas
  • ./references/accessibility-patterns.md — ARIA, formularios, jerarquía de encabezados
  • ./examples/button-component/ — Ejemplo completo de Button con CSS Module

Archivos de Configuración

  • astro.config.mjs — Configuración principal del proyecto (integraciones, output, adaptador, etc.)
  • src/content.config.ts — Esquemas y cargadores de colecciones de contenido
  • src/actions/index.ts — Acciones de servidor tipificadas
  • src/middleware.ts — Lógica de middleware

Puntos Clave a Recordar

  1. Astro para estructura estática; SolidJS/React para interactividad. No hay excepciones.
  2. Módulos CSS siempre en archivos separados. Nunca estilos dentro de <style> o en línea.
  3. Directiva de hidratación mínima. Empieza con client:visible o client:idle.
  4. Componentes fundamentales siempre son islas. Nunca archivos .astro.
  5. Una carpeta por componente. Archivo principal (index.astro o index.tsx) más styles.module.css.
  6. Datos desde páginas hacia abajo. Consultas en frontmatter de página, props en componentes.
  7. HTML semántico y accesible. Sin divs genéricos cuando hay un elemento semántico disponible.

Skills relacionados