# Astro Improvements
Skill to audit an Astro application, detect anti-patterns across four dimensions, and produce a prioritized report with concrete before/after refactor recipes.
## When to Use
- Before a production release to catch regressions
- When performance budget alerts fire (LCP, CLS, bundle size)
- During onboarding to an unfamiliar Astro codebase
- After migrating from SSG to SSR (or vice versa)
- Suspicion of over-hydration or unnecessary client JavaScript
- Routine accessibility or SEO audit
## Dimensions
| Dimension | Weight | Focus |
|-----------|--------|-------|
| ⚡ **Performance & Islands** | 30% | `client:*` directives, hydration cost, `<Image>`, prefetch, bundle size |
| 🏗️ **Architecture & Structure** | 25% | Layouts, content collections, routing, SSR vs SSG, `astro.config.mjs` |
| 🔍 **SEO, Accessibility & Meta** | 25% | Semantic HTML, ARIA, sitemap, robots, Open Graph, `lang`, headings |
| 🛠️ **DX, TypeScript & Quality** | 20% | `tsconfig`, env types, `Props` interfaces, linting, `astro check` in CI |
## Process
### Step 1: Inventory
Read in this order:
- `astro.config.mjs` — output mode (SSG/SSR/hybrid), integrations, adapters
- `package.json` — Astro version, framework integrations, bundle tools
- `src/` tree — layouts, pages, components, content, middleware
- `public/` — static assets that bypass Astro's asset pipeline
Flag:
```
✅ output mode is explicit and intentional
✅ only needed integrations are listed
⚠️ mixed .astro and framework components (React/Vue) without clear boundary
❌ no astro.config.mjs found → cannot proceed reliably
```
### Step 2: Map findings to dimensions
For each file or pattern found, assign it to one of the four dimensions and note the relevant path (`src/components/Card.astro:12`).
### Step 3: Score severity
| Severity | Criteria |
|----------|----------|
| 🔴 **Critical** | Blocks SEO indexing, breaks a11y for assistive tech, or sends 100+ KB unnecessary JS to every visitor |
| 🟡 **Major** | Degrades Core Web Vitals, creates confusing architecture, or causes DX friction in every feature |
| 🟢 **Minor** | Polish issue — measurable improvement but no immediate impact |
### Step 4: Propose refactors
For every 🔴 Critical and 🟡 Major finding, provide a before/after snippet. For 🟢 Minor findings a one-line fix is enough.
### Step 5: Emit report
Use the [Report Template](#report-template) at the end of this skill.
---
## Catalog of Improvements
### ⚡ Performance & Islands
#### `client:load` used for static content — 🔴 Critical
Every `client:load` sends a full framework bundle to the browser before the page is interactive. Reserve it for components that actually need browser APIs on load.
```astro
<!-- ❌ Before — sends React bundle even though Card is pure HTML -->
<Card client:load title="Hello" />
<!-- ✅ After — no directive: rendered to static HTML at build time -->
<Card title="Hello" />
<!-- ✅ After — interactive only when scrolled into view -->
<Counter client:visible initialCount={0} />
```
**Fix:** Audit every `client:*` directive. Use `client:visible` for below-the-fold interactivity, `client:idle` for low-priority widgets, and no directive for fully static components.
---
#### Raw `<img>` instead of `<Image>` — 🟡 Major
Astro's built-in `<Image>` component generates responsive `srcset`, converts to WebP/AVIF, and adds width/height to prevent layout shift. Raw `<img>` tags skip all of this.
```astro
<!-- ❌ Before -->
<img src="/hero.jpg" alt="Hero" />
<!-- ✅ After -->
---
import { Image } from 'astro:assets';
import heroImg from '../assets/hero.jpg';
---
<Image src={heroImg} alt="Hero" width={1200} height={600} />
```
**Fix:** Replace `<img src="...">` with `<Image>` for all local and remote images. Set `image.remotePatterns` in `astro.config.mjs` for external sources.
---
#### No prefetch strategy — 🟢 Minor
Astro supports automatic link prefetching with a single config line. Without it, navigations feel slower than necessary on multi-page sites.
```js
// ❌ Before — astro.config.mjs, no prefetch config
export default defineConfig({ ... });
// ✅ After — prefetch on hover, opt-out per link with data-astro-prefetch="false"
export default defineConfig({
prefetch: { prefetchAll: false, defaultStrategy: 'hover' }
});
```
**Fix:** Add `prefetch` config to `astro.config.mjs`. Use `prefetchAll: true` only for small sites with few pages.
---
### 🏗️ Architecture & Structure
#### Front matter logic instead of Content Collections — 🔴 Critical
Embedding data arrays or fetch logic directly in `.astro` page front matter bypasses type safety and makes content unqueryable.
```astro
<!-- ❌ Before — data hardcoded in page front matter -->
---
const posts = [
{ title: 'Post 1', date: '2024-01-01', slug: 'post-1' },
{ title: 'Post 2', date: '2024-02-01', slug: 'post-2' },
];
---
<!-- ✅ After — define a collection with schema -->
```
```ts
// src/content/config.ts
import { defineCollection, z } from 'astro:content';
export const collections = {
blog: defineCollection({
schema: z.object({ title: z.string(), date: z.coerce.date() }),
}),
};
```
```astro
<!-- src/pages/blog/index.astro -->
---
import { getCollection } from 'astro:content';
const posts = await getCollection('blog');
---
```
**Fix:** Move repeated data into `src/content/{collection}/` with a Zod schema in `src/content/config.ts`. Use `getCollection()` to query with full TypeScript inference.
---
#### Duplicate layout wrappers — 🟡 Major
Copy-pasted `<html>`, `<head>`, and `<body>` boilerplate across pages makes global changes (CSP headers, fonts, analytics) error-prone.
```astro
<!-- ❌ Before — same <head> repeated in every page -->
---
// src/pages/index.astro AND src/pages/about.astro
---
<html lang="en">
<head><title>...</title><link rel="stylesheet" .../></head>
<body>...</body>
</html>
<!-- ✅ After — one Layout component -->
---
import Layout from '../layouts/Layout.astro';
---
<Layout title="Home">
<main>...</main>
</Layout>
```
**Fix:** Extract a `src/layouts/Layout.astro` that owns `<html>`, `<head>`, and global styles. Pass `title` and `description` as props.
---
#### Unused integrations in `astro.config.mjs` — 🟢 Minor
Every registered integration runs at build time. Leftover integrations from experiments increase build time and can introduce unexpected transformations.
```js
// ❌ Before — @astrojs/react listed but no .jsx/.tsx files exist
import react from '@astrojs/react';
export default defineConfig({ integrations: [react()] });
// ✅ After — only integrations actually in use
export default defineConfig({ integrations: [sitemap()] });
```
**Fix:** Cross-check `integrations` with `src/` — if no component files use a framework, remove its integration and package.
---
### 🔍 SEO, Accessibility & Meta
#### Missing `lang` attribute on `<html>` — 🔴 Critical
Screen readers and search engines need `lang` to parse content correctly. Its absence is a WCAG 2.1 Level A failure.
```astro
<!-- ❌ Before -->
<html>
<!-- ✅ After -->
<html lang="en">
```
**Fix:** Add `lang` to the root `<html>` in every layout. Accept it as a prop (`lang = 'en'`) for multilingual sites.
---
#### Missing Open Graph and meta description — 🟡 Major
Pages without `og:title`, `og:description`, and `description` meta appear as bare URLs when shared on social platforms and rank lower in search results.
```astro
<!-- ❌ Before — Layout.astro head has only a <title> -->
<head>
<title>{title}</title>
</head>
<!-- ✅ After -->
<head>
<title>{title}</title>
<meta name="description" content={description} />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:type" content="website" />
<meta property="og:image" content={new URL(ogImage, Astro.url)} />
</head>
```
**Fix:** Add a `<SEO>` component or extend the Layout props to accept `description` and `ogImage`. Make `description` required via TypeScript.
---
#### Skipped heading levels — 🟡 Major
Jumping from `<h1>` to `<h3>` breaks the document outline used by screen readers and degrades SEO heading structure.
```astro
<!-- ❌ Before -->
<h1>Blog</h1>
<h3>Latest Posts</h3> <!-- h2 is missing -->
<!-- ✅ After -->
<h1>Blog</h1>
<h2>Latest Posts</h2>
<h3>{post.title}</h3>
```
**Fix:** Enforce one `<h1>` per page and sequential levels. Use browser DevTools › Accessibility pane or axe to audit the heading tree.
---
### 🛠️ DX, TypeScript & Quality
#### `strict: false` in `tsconfig.json` — 🔴 Critical
Disabling strict mode masks `null`/`undefined` errors, implicit `any` types, and unchecked function parameters — all common sources of runtime bugs in Astro components.
```jsonc
// ❌ Before
{ "extends": "astro/tsconfigs/base", "compilerOptions": { "strict": false } }
// ✅ After — use the strictest preset Astro ships
{ "extends": "astro/tsconfigs/strictest" }
```
**Fix:** Replace with `astro/tsconfigs/strictest` (or at minimum `astro/tsconfigs/strict`). Fix resulting type errors before enabling — do not suppress with `// @ts-ignore`.
---
#### `import.meta.env` without type declarations — 🟡 Major
Accessing custom env variables without an `env.d.ts` declaration means TypeScript treats them as `any`, silencing typos in variable names.
```ts
// ❌ Before — no env.d.ts, IDE has no autocomplete
const key = import.meta.env.PUBLIC_API_KEY; // type: any
// ✅ After — src/env.d.ts
/// <reference types="astro/client" />
interface ImportMetaEnv {
readonly PUBLIC_API_KEY: string;
readonly SECRET_DB_URL: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
```
**Fix:** Create `src/env.d.ts` with typed declarations for every env variable. Add a check to CI that fails if `.env.example` variables are missing from `env.d.ts`.
---
#### Components without `Props` interface — 🟢 Minor
Untyped component props prevent IDE autocompletion and let callers pass wrong values silently.
```astro
<!-- ❌ Before — no prop types -->
---
const { title, count } = Astro.props;
---
<!-- ✅ After -->
---
interface Props {
title: string;
count?: number;
}
const { title, count = 0 } = Astro.props;
---
```
**Fix:** Add an `interface Props` block to every `.astro` component that accepts props. Use `astro check` (see below) to surface violations.
---
## Report Template
````markdown
# Astro Improvements — {project name}
## 📊 Overall Score: {X}/100
| Dimension | Score | Status |
|-----------|-------|--------|
| ⚡ Performance & Islands | {X}/30 | {✅ ⚠️ ❌} |
| 🏗️ Architecture & Structure | {X}/25 | {✅ ⚠️ ❌} |
| 🔍 SEO, Accessibility & Meta | {X}/25 | {✅ ⚠️ ❌} |
| 🛠️ DX, TypeScript & Quality | {X}/20 | {✅ ⚠️ ❌} |
## Verdict
{🟢 SHIP | 🟡 SHIP WITH MINOR FIXES | 🔴 NEEDS WORK BEFORE SHIPPING}
## Findings
| # | Severity | Dimension | Location | Effort |
|---|----------|-----------|----------|--------|
| 1 | 🔴 Critical | Performance | `src/components/Hero.astro:8` | S |
| 2 | 🟡 Major | Architecture | `src/pages/blog/index.astro:3–18` | M |
## Detailed Findings
### Finding 1 — {title}
**File:** `src/...`
**Why it matters:** ...
**Before:**
```astro
...
```
**After:**
```astro
...
```
## Top 5 Action Plan
1. [ ] {Most impactful fix — link to finding}
2. [ ] ...
3. [ ] ...
4. [ ] ...
5. [ ] ...
## Checklist
- [ ] No `client:load` on purely static components
- [ ] All `<img>` tags replaced with `<Image>`
- [ ] `astro.config.mjs` integrations match actual usage
- [ ] Every layout has `lang` on `<html>`
- [ ] `og:title`, `og:description`, `description` present on all pages
- [ ] No skipped heading levels
- [ ] `tsconfig.json` extends `astro/tsconfigs/strictest`
- [ ] `src/env.d.ts` types all `import.meta.env` variables
- [ ] All components have a `Props` interface
- [ ] `astro check` runs in CI with zero errors
````
## Heuristics & Quick Wins
- If `client:load` is on a component with no event handlers or browser API calls → remove the directive entirely.
- If `astro.config.mjs` output is `'server'` but every page has no dynamic data → switch to `'static'` and remove the adapter.
- If `@astrojs/sitemap` is absent and the site is SSG → add it; search engines won't automatically discover all pages.
- If a page has two or more `<h1>` tags → refactor so only the page title uses `<h1>`.
- If `astro check` is not in the CI pipeline → add it before the build step; it catches type errors that TypeScript alone misses in `.astro` files.
# Mejoras en Astro
Skill para auditar una aplicación Astro, detectar antipatrones en cuatro dimensiones y producir un informe priorizado con recetas concretas de refactorización con ejemplos Antes/Después.
## Cuándo Usar
- Antes de un lanzamiento a producción para detectar regresiones
- Cuando salten alertas de presupuesto de rendimiento (LCP, CLS, tamaño de bundle)
- Al incorporarse a una codebase Astro desconocida
- Tras migrar de SSG a SSR (o viceversa)
- Sospecha de over-hydration o JavaScript innecesario en el cliente
- Auditoría rutinaria de accesibilidad o SEO
## Dimensiones
| Dimensión | Peso | Foco |
|-----------|------|------|
| ⚡ **Performance & Islands** | 30% | Directivas `client:*`, coste de hidratación, `<Image>`, prefetch, tamaño de bundle |
| 🏗️ **Architecture & Structure** | 25% | Layouts, content collections, routing, SSR vs SSG, `astro.config.mjs` |
| 🔍 **SEO, Accesibilidad y Meta** | 25% | HTML semántico, ARIA, sitemap, robots, Open Graph, atributo `lang`, headings |
| 🛠️ **DX, TypeScript y Calidad** | 20% | `tsconfig`, tipos de env, interfaces `Props`, linting, `astro check` en CI |
## Proceso
### Paso 1: Inventario
Leer en este orden:
- `astro.config.mjs` — modo de salida (SSG/SSR/hybrid), integraciones, adaptadores
- `package.json` — versión de Astro, integraciones de framework, herramientas de bundle
- Árbol de `src/` — layouts, páginas, componentes, content, middleware
- `public/` — assets estáticos que no pasan por el pipeline de Astro
Verificar:
```
✅ El modo de salida es explícito e intencionado
✅ Solo están listadas las integraciones necesarias
⚠️ Mezcla de .astro y componentes de framework (React/Vue) sin límite claro
❌ No se encuentra astro.config.mjs → no es posible continuar con fiabilidad
```
### Paso 2: Mapear hallazgos a dimensiones
Por cada archivo o patrón detectado, asignarlo a una de las cuatro dimensiones e indicar la ruta relevante (`src/components/Card.astro:12`).
### Paso 3: Puntuar severidad
| Severidad | Criterio |
|-----------|----------|
| 🔴 **Crítico** | Bloquea la indexación SEO, rompe la accesibilidad para tecnologías asistivas, o envía más de 100 KB de JS innecesario a cada visitante |
| 🟡 **Mayor** | Degrada Core Web Vitals, genera arquitectura confusa o causa fricción de DX en cada funcionalidad |
| 🟢 **Menor** | Problema de pulido — mejora medible pero sin impacto inmediato |
### Paso 4: Proponer refactorizaciones
Para cada hallazgo 🔴 Crítico y 🟡 Mayor, proporcionar un fragmento Antes/Después. Para los hallazgos 🟢 Menores basta una corrección de una línea.
### Paso 5: Emitir informe
Usar la [Plantilla de Informe](#plantilla-de-informe) al final de esta skill.
---
## Catálogo de Mejoras
### ⚡ Performance & Islands
#### `client:load` usado en contenido estático — 🔴 Crítico
Cada `client:load` envía el bundle completo del framework al navegador antes de que la página sea interactiva. Reservarlo para componentes que realmente necesiten APIs del navegador al cargar.
```astro
<!-- ❌ Antes — envía el bundle de React aunque Card sea HTML puro -->
<Card client:load title="Hola" />
<!-- ✅ Después — sin directiva: se renderiza a HTML estático en build time -->
<Card title="Hola" />
<!-- ✅ Después — interactivo solo cuando entra en el viewport -->
<Counter client:visible initialCount={0} />
```
**Corrección:** Auditar cada directiva `client:*`. Usar `client:visible` para interactividad bajo el pliegue, `client:idle` para widgets de baja prioridad, y ninguna directiva para componentes completamente estáticos.
---
#### `<img>` sin `<Image>` — 🟡 Mayor
El componente `<Image>` de Astro genera `srcset` responsive, convierte a WebP/AVIF y añade ancho/alto para evitar layout shift. Las etiquetas `<img>` normales omiten todo esto.
```astro
<!-- ❌ Antes -->
<img src="/hero.jpg" alt="Hero" />
<!-- ✅ Después -->
---
import { Image } from 'astro:assets';
import heroImg from '../assets/hero.jpg';
---
<Image src={heroImg} alt="Hero" width={1200} height={600} />
```
**Corrección:** Reemplazar `<img src="...">` por `<Image>` en todas las imágenes locales y remotas. Configurar `image.remotePatterns` en `astro.config.mjs` para fuentes externas.
---
#### Sin estrategia de prefetch — 🟢 Menor
Astro soporta prefetching automático de enlaces con una sola línea de configuración. Sin él, las navegaciones se sienten más lentas de lo necesario en sitios multipágina.
```js
// ❌ Antes — astro.config.mjs sin configuración de prefetch
export default defineConfig({ ... });
// ✅ Después — prefetch al pasar el cursor, opt-out por enlace con data-astro-prefetch="false"
export default defineConfig({
prefetch: { prefetchAll: false, defaultStrategy: 'hover' }
});
```
**Corrección:** Añadir configuración de `prefetch` a `astro.config.mjs`. Usar `prefetchAll: true` solo en sitios pequeños con pocas páginas.
---
### 🏗️ Architecture & Structure
#### Lógica en el front matter en lugar de Content Collections — 🔴 Crítico
Incrustar arrays de datos o lógica de fetch directamente en el front matter de páginas `.astro` elimina la seguridad de tipos y hace el contenido no consultable.
```astro
<!-- ❌ Antes — datos hardcodeados en el front matter de la página -->
---
const posts = [
{ title: 'Post 1', date: '2024-01-01', slug: 'post-1' },
{ title: 'Post 2', date: '2024-02-01', slug: 'post-2' },
];
---
<!-- ✅ Después — definir una colección con schema -->
```
```ts
// src/content/config.ts
import { defineCollection, z } from 'astro:content';
export const collections = {
blog: defineCollection({
schema: z.object({ title: z.string(), date: z.coerce.date() }),
}),
};
```
```astro
<!-- src/pages/blog/index.astro -->
---
import { getCollection } from 'astro:content';
const posts = await getCollection('blog');
---
```
**Corrección:** Mover los datos repetidos a `src/content/{coleccion}/` con un schema Zod en `src/content/config.ts`. Usar `getCollection()` para consultar con inferencia completa de TypeScript.
---
#### Layouts duplicados — 🟡 Mayor
El boilerplate de `<html>`, `<head>` y `<body>` copiado entre páginas hace que los cambios globales (cabeceras CSP, fuentes, analytics) sean propensos a errores.
```astro
<!-- ❌ Antes — el mismo <head> repetido en cada página -->
<html lang="es">
<head><title>...</title><link rel="stylesheet" .../></head>
<body>...</body>
</html>
<!-- ✅ Después — un único componente Layout -->
---
import Layout from '../layouts/Layout.astro';
---
<Layout title="Inicio">
<main>...</main>
</Layout>
```
**Corrección:** Extraer un `src/layouts/Layout.astro` que sea propietario de `<html>`, `<head>` y los estilos globales. Pasar `title` y `description` como props.
---
#### Integraciones sin uso en `astro.config.mjs` — 🟢 Menor
Cada integración registrada se ejecuta en build time. Las integraciones sobrantes de experimentos aumentan el tiempo de build y pueden introducir transformaciones inesperadas.
```js
// ❌ Antes — @astrojs/react listado pero sin archivos .jsx/.tsx
import react from '@astrojs/react';
export default defineConfig({ integrations: [react()] });
// ✅ Después — solo las integraciones realmente en uso
export default defineConfig({ integrations: [sitemap()] });
```
**Corrección:** Cruzar las `integrations` con `src/` — si ningún archivo de componentes usa un framework, eliminar su integración y su paquete.
---
### 🔍 SEO, Accesibilidad y Meta
#### Falta el atributo `lang` en `<html>` — 🔴 Crítico
Los lectores de pantalla y los motores de búsqueda necesitan `lang` para interpretar el contenido correctamente. Su ausencia es un fallo WCAG 2.1 Nivel A.
```astro
<!-- ❌ Antes -->
<html>
<!-- ✅ Después -->
<html lang="es">
```
**Corrección:** Añadir `lang` al `<html>` raíz en cada layout. Aceptarlo como prop (`lang = 'es'`) en sitios multilingüe.
---
#### Falta Open Graph y meta description — 🟡 Mayor
Las páginas sin `og:title`, `og:description` y `description` aparecen como URLs desnudas cuando se comparten en redes sociales y posicionan peor en búsquedas.
```astro
<!-- ❌ Antes — Layout.astro head solo con <title> -->
<head>
<title>{title}</title>
</head>
<!-- ✅ Después -->
<head>
<title>{title}</title>
<meta name="description" content={description} />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:type" content="website" />
<meta property="og:image" content={new URL(ogImage, Astro.url)} />
</head>
```
**Corrección:** Añadir un componente `<SEO>` o extender las props del Layout para aceptar `description` e `ogImage`. Hacer `description` obligatorio vía TypeScript.
---
#### Niveles de heading saltados — 🟡 Mayor
Saltar de `<h1>` a `<h3>` rompe el esquema del documento que usan los lectores de pantalla y degrada la estructura de headings para SEO.
```astro
<!-- ❌ Antes -->
<h1>Blog</h1>
<h3>Últimas entradas</h3> <!-- falta h2 -->
<!-- ✅ Después -->
<h1>Blog</h1>
<h2>Últimas entradas</h2>
<h3>{post.title}</h3>
```
**Corrección:** Aplicar un solo `<h1>` por página y niveles secuenciales. Usar el panel de Accesibilidad de DevTools o axe para auditar el árbol de headings.
---
### 🛠️ DX, TypeScript y Calidad
#### `strict: false` en `tsconfig.json` — 🔴 Crítico
Deshabilitar el modo estricto oculta errores de `null`/`undefined`, tipos `any` implícitos y parámetros de función sin verificar — fuentes habituales de errores en runtime en componentes Astro.
```jsonc
// ❌ Antes
{ "extends": "astro/tsconfigs/base", "compilerOptions": { "strict": false } }
// ✅ Después — usar el preset más estricto que incluye Astro
{ "extends": "astro/tsconfigs/strictest" }
```
**Corrección:** Reemplazar por `astro/tsconfigs/strictest` (o como mínimo `astro/tsconfigs/strict`). Corregir los errores de tipo resultantes antes de activarlo — no suprimir con `// @ts-ignore`.
---
#### `import.meta.env` sin declaraciones de tipos — 🟡 Mayor
Acceder a variables de entorno personalizadas sin un `env.d.ts` hace que TypeScript las trate como `any`, ocultando errores tipográficos en los nombres de variable.
```ts
// ❌ Antes — sin env.d.ts, el IDE no tiene autocompletado
const key = import.meta.env.PUBLIC_API_KEY; // tipo: any
// ✅ Después — src/env.d.ts
/// <reference types="astro/client" />
interface ImportMetaEnv {
readonly PUBLIC_API_KEY: string;
readonly SECRET_DB_URL: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
```
**Corrección:** Crear `src/env.d.ts` con declaraciones tipadas para cada variable de entorno. Añadir una verificación en CI que falle si las variables de `.env.example` no están en `env.d.ts`.
---
#### Componentes sin interfaz `Props` — 🟢 Menor
Las props sin tipos impiden el autocompletado del IDE y permiten que los consumidores pasen valores incorrectos sin advertencia.
```astro
<!-- ❌ Antes — sin tipos de props -->
---
const { title, count } = Astro.props;
---
<!-- ✅ Después -->
---
interface Props {
title: string;
count?: number;
}
const { title, count = 0 } = Astro.props;
---
```
**Corrección:** Añadir un bloque `interface Props` a cada componente `.astro` que acepte props. Usar `astro check` (ver más abajo) para detectar violaciones.
---
## Plantilla de Informe
````markdown
# Mejoras en Astro — {nombre del proyecto}
## 📊 Puntuación Global: {X}/100
| Dimensión | Puntuación | Estado |
|-----------|-----------|--------|
| ⚡ Performance & Islands | {X}/30 | {✅ ⚠️ ❌} |
| 🏗️ Architecture & Structure | {X}/25 | {✅ ⚠️ ❌} |
| 🔍 SEO, Accesibilidad y Meta | {X}/25 | {✅ ⚠️ ❌} |
| 🛠️ DX, TypeScript y Calidad | {X}/20 | {✅ ⚠️ ❌} |
## Veredicto
{🟢 LISTO PARA PRODUCCIÓN | 🟡 LISTO CON CORRECCIONES MENORES | 🔴 REQUIERE TRABAJO ANTES DE PRODUCCIÓN}
## Hallazgos
| # | Severidad | Dimensión | Ubicación | Esfuerzo |
|---|-----------|-----------|-----------|---------|
| 1 | 🔴 Crítico | Performance | `src/components/Hero.astro:8` | S |
| 2 | 🟡 Mayor | Architecture | `src/pages/blog/index.astro:3–18` | M |
## Hallazgos Detallados
### Hallazgo 1 — {título}
**Archivo:** `src/...`
**Por qué importa:** ...
**Antes:**
```astro
...
```
**Después:**
```astro
...
```
## Plan de Acción — Top 5
1. [ ] {Corrección de mayor impacto — enlace al hallazgo}
2. [ ] ...
3. [ ] ...
4. [ ] ...
5. [ ] ...
## Checklist
- [ ] Sin `client:load` en componentes puramente estáticos
- [ ] Todas las etiquetas `<img>` reemplazadas por `<Image>`
- [ ] Las integraciones de `astro.config.mjs` coinciden con el uso real
- [ ] Cada layout tiene `lang` en `<html>`
- [ ] `og:title`, `og:description` y `description` presentes en todas las páginas
- [ ] Sin niveles de heading saltados
- [ ] `tsconfig.json` extiende `astro/tsconfigs/strictest`
- [ ] `src/env.d.ts` tipifica todas las variables de `import.meta.env`
- [ ] Todos los componentes tienen una interfaz `Props`
- [ ] `astro check` se ejecuta en CI sin errores
````
## Heurísticas y Quick Wins
- Si `client:load` está en un componente sin event handlers ni llamadas a APIs del navegador → eliminar la directiva por completo.
- Si el output de `astro.config.mjs` es `'server'` pero cada página carece de datos dinámicos → cambiar a `'static'` y eliminar el adaptador.
- Si `@astrojs/sitemap` no está presente y el sitio es SSG → añadirlo; los motores de búsqueda no descubrirán automáticamente todas las páginas.
- Si una página tiene dos o más etiquetas `<h1>` → refactorizar para que solo el título de página use `<h1>`.
- Si `astro check` no está en el pipeline de CI → añadirlo antes del paso de build; detecta errores de tipo que TypeScript solo no detecta en archivos `.astro`.