Category: Astro

  • Astro 7.3: el candado que bloqueaba tus tests E2E en preview

    Astro 7.3: el candado que bloqueaba tus tests E2E en preview

    Actualizas Astro. Lanzas la suite de Playwright. Un servidor de preview arranca bien y los demás se caen con un error que no habla de tus tests: habla de un lockfile.

    Tú no habías puesto ningún lockfile. Y el commit de esa noche no tocaba nada de testing.

    Ese error tiene una historia detrás, y la historia no va de ti. Va de los agentes de IA.

    Astro 7.3.0 se publicó el 3 de septiembre de 2026 con tres cambios pequeños: el flag --ignore-lock llega a astro preview, el logger de runtime de Astro se pasa a los image services y cache providers custom, y @astrojs/cloudflare 14.3.0 incorpora un helper finalize() para worker entrypoints propios. No hay breaking changes. Ninguno de los tres cambia lo que puedes construir con Astro; los tres cambian cuánto tiempo pierdes cuando algo se rompe.

    Todo lo que cuento aquí sale de las notas oficiales de la release de Astro 7.3, del changelog de astro 7.3.0, del changelog de @astrojs/cloudflare y de la referencia de CLI de Astro.

    Vamos con el primero, que es el que más gente va a notar hoy mismo.


    --ignore-lock llega a astro preview: el arreglo que se nota en el CI

    astro preview levanta un servidor sobre tu build de producción. Es contra ese servidor contra el que corren tus tests E2E, porque probar contra astro dev es probar otra cosa: otro pipeline, otros assets, otro comportamiento.

    Desde Astro 7.2, ese comando escribe un lockfile en .astro/preview.json — el mismo mecanismo que astro dev usa en .astro/dev.json desde Astro 7.0. Un servidor de preview por proyecto y punto: si intentas levantar el segundo, no arranca.

    Astro 7.3 devuelve la escotilla:

    npx astro preview --port 4322 --ignore-lock
    

    El flag se salta la comprobación del lockfile y te deja arrancar tantos servidores de preview como quieras sobre el mismo proyecto, cada uno en su puerto. En Playwright, que es el caso de uso que el propio equipo de Astro menciona en las notas, se traduce en esto:

    // playwright.config.ts
    import { defineConfig } from '@playwright/test';
    
    export default defineConfig({
      webServer: [
        {
          command: 'npx astro preview --port 4321 --ignore-lock',
          url: 'http://localhost:4321',
          reuseExistingServer: !process.env.CI,
        },
        {
          command: 'npx astro preview --port 4322 --ignore-lock',
          url: 'http://localhost:4322',
          reuseExistingServer: !process.env.CI,
        },
      ],
    });
    

    Hay un detalle que conviene leer dos veces. Las notas oficiales avisan de que estas instancias corren de forma independiente, así que están pensadas para servidores rápidos y de usar y tirar, no para los que gestionas con astro preview stop o astro preview status. Traducido: si los arrancas a mano, los matas a mano. Dentro de Playwright da igual, porque el teardown del webServer se encarga.

    Y un aviso que no está en el anuncio de la release pero sí en la referencia del CLI: --ignore-lock no se puede combinar con --background ni con --force, porque los dos dependen del lockfile. Si los juntas, Astro lanza un error.

    Lo que convierte eso en un problema real: Astro activa el modo background por su cuenta cuando detecta que quien ejecuta el comando es un agente de IA. Traducido: si lanzas la suite desde dentro de una sesión de Claude Code o de Cursor, tu --ignore-lock puede petar sin que hayas escrito --background en ninguna parte.

    La salida está documentada y es una variable de entorno:

    ASTRO_PREVIEW_BACKGROUND=0 npx astro preview --port 4322 --ignore-lock
    

    Si lanzas Playwright desde tu terminal, esto no te afecta. Si lo lanza un agente por ti, ponla en el webServer y te ahorras el segundo día de depuración.

    Y hay un segundo escenario, menos obvio y más frecuente de lo que parece: no necesitas dos suites en paralelo para chocar con el candado. Basta con que algo ya lo tenga cogido. Un preview huérfano de la ejecución anterior. O tu agente de IA, que dejó uno levantado en segundo plano mientras trabajaba.

    Esto último no es hipotético, y aquí es donde la release se pone interesante.


    El candado no lo pusieron por ti

    Astro 7 introdujo el lockfile en astro dev con un motivo explícito, y lo dicen ellos con todas las letras en su blog: para que los agentes de IA no levantaran servidores de desarrollo duplicados del mismo proyecto sin darse cuenta. Un problema que hace tres años no existía.

    La secuencia completa es esta:

    Versión Qué pasó
    Astro 7.0 Llega el lockfile a astro dev para frenar servidores duplicados de agentes de IA
    Astro 7.1 Se añade --ignore-lock a astro dev para quien sí quiere varios a propósito
    Astro 7.2 El lockfile se extiende a astro preview, pero sin escotilla
    Astro 7.3 --ignore-lock llega también a astro preview

    Si te interesa el contexto de dónde salió todo esto, lo conté cuando salió la major en el repaso de novedades de Astro v7.

    Aquí está la lección, y va mucho más allá de Astro.

    Tus herramientas están empezando a poner defaults pensados para un agente, no para ti. El lockfile es una decisión sensata cuando quien ejecuta el comando es un modelo que no recuerda si ya levantó el servidor hace diez minutos. Es una decisión molesta cuando quien lo ejecuta eres tú, con un playwright.config.ts delante y muy claro lo que quieres.

    Astro lo ha resuelto bien: default seguro para el agente, flag explícito para el humano. Pero el patrón se va a repetir en todo tu stack, y la próxima vez a lo mejor no te dan el flag el mismo trimestre.

    Por eso insisto tanto en esto cuando trabajo con agentes en el curso de Construye con IA: tienes que saber qué procesos deja vivos tu agente. No porque vaya a romper nada grave, sino porque el día que tu CI falle por un lockfile vas a perder dos horas buscando el bug en tu código.

    Y ya que estamos en testing: el E2E es la capa cara. Casi todo lo que quieres verificar debería estar cubierto más abajo, donde una prueba cuesta milisegundos — lo desarrollé en pruebas unitarias ultrarrápidas con Vitest.


    El logger de runtime llega a los image services y a los cache providers

    Segundo cambio. Menos vistoso, y sin embargo es el que arregla un problema de higiene real.

    Si mantienes un image service custom —el típico wrapper sobre Cloudinary, imgproxy o tu propio CDN— hasta ahora tu única forma de avisar de algo era console.warn(). Con la consecuencia obvia: ese warning se escupía siempre. Ignoraba el nivel de log del proyecto, ignoraba --silent y ensuciaba la salida del build igual en local que en CI.

    En Astro 7.3, los image services reciben el logger de Astro como argumento adicional en transform():

    import type { LocalImageService } from 'astro';
    
    const service: LocalImageService = {
      // ...
      async transform(inputBuffer, transform, imageConfig, logger) {
        logger.warn(`No se pudo optimizar "${transform.src}". Se devuelve sin tocar.`);
        return { data: inputBuffer, format: 'png' };
      },
    };
    

    Y los cache providers lo reciben dentro del contexto que se pasa a onRequest():

    import type { CacheProvider } from 'astro';
    
    const provider: CacheProvider = {
      name: 'my-cache',
      async onRequest({ request, url, logger }, next) {
        logger.warn(`Caché omitida en ${url.pathname}: la respuesta define una cookie.`);
        return next();
      },
      // ...
    };
    

    El servicio Sharp integrado y el provider memoryCache() ya están migrados. Sharp lo usa para avisar de formatos de origen raros o no soportados; memoryCache(), para avisar de respuestas que se salta y de fallos en la revalidación en segundo plano.

    La ganancia no es que ahora "haya logs". Es que tus warnings viajan por el mismo canal que los de Astro y respetan la configuración del proyecto. Si mantienes una integración propia, es un cambio de dos líneas.

    Y sí, esto entra de lleno en la conversación de rendimiento: el image service es una de las piezas que decide el peso real de tus páginas, igual que las Server Islands que analicé en sitios web ultrarrápidos con Astro.


    finalize() en @astrojs/cloudflare: el bug silencioso de las cookies

    Tercer cambio, el más de nicho y el más peligroso de los tres si te toca.

    Va para quien despliega en Cloudflare con un worker entrypoint propio en lugar del que genera el adapter. Ese pipeline manual funciona, pero se salta un paso: aplicar las cookies y los defaults de caché del CDN de Cloudflare a la respuesta que devuelve astro/fetch.

    Un bug de esos que no rompe el build. Simplemente un día descubres que las cookies de sesión no llegan.

    @astrojs/cloudflare 14.3.0, publicada el 3 de septiembre de 2026 —el mismo día que Astro 7.3—, añade finalize() para cerrar ese hueco. Recibe el FetchState y la respuesta del pipeline, y devuelve la respuesta ya con las cookies y la caché aplicadas:

    // src/worker.ts
    import { astro, FetchState } from 'astro/fetch';
    import { cf, finalize } from '@astrojs/cloudflare/fetch';
    
    export default {
      async fetch(request: Request, env: Env, context: ExecutionContext) {
        const state = new FetchState(request);
        const asset = await cf(state, env, context);
        if (asset) return asset;
    
        return finalize(state, await astro(state));
      },
    };
    

    Si usas Hono, no tienes que hacer nada: el middleware @astrojs/cloudflare/hono aplica esas cabeceras por su cuenta.

    El resto de la release te ahorra tiempo. Esta te ahorra un incidente.


    ¿Te toca actualizar a Astro 7.3?

    No hay breaking changes, así que la pregunta no es si puedes, es si ganas algo.

    Tu situación Qué hacer Por qué
    Tienes E2E con Playwright sobre astro preview Actualiza hoy Es la diferencia entre una suite que arranca y una que muere en el webServer
    Trabajas a diario con un agente de IA en el proyecto Actualiza hoy Dejas de pelearte con él por el mismo lockfile
    Mantienes un image service o cache provider custom Actualiza y cambia dos líneas Tus warnings pasan a respetar el nivel de log y --silent
    Despliegas en Cloudflare con worker entrypoint propio Sube @astrojs/cloudflare a 14.3.0 finalize() te quita el bug silencioso de las cookies
    Sitio estático, sin E2E, sin adapter Actualiza sin prisa No hay riesgo, pero tampoco premio

    Si vienes de la rama 6.x, el salto que de verdad cambió cómo se construye con Astro no es este: fue el de Server Islands y Actions en 6.2. Astro 7.3 es mantenimiento fino sobre esa base.


    Lo que yo haría esta semana

    Abre tu playwright.config.ts y mira si el command del webServer llama a astro preview. Si es que sí, añade --ignore-lock y actualiza. Son treinta segundos y te ahorras el día en que el CI falle por un lockfile que tú no pusiste.

    El resto puede esperar al próximo sprint.

    Pero quédate con la idea de fondo, porque vale más que los tres cambios juntos: tu tooling ha empezado a asumir que quien escribe los comandos es un agente. Los defaults se están moviendo hacia ahí. Cuando algo se rompa de forma rara en tu pipeline, esa es la primera hipótesis que deberías poner sobre la mesa, y ya no la última.

    De esto discutimos bastante en Dominicode Labs, porque casi todos los que estamos metiendo agentes en el flujo diario nos hemos comido alguna versión de este mismo problema.


    Preguntas frecuentes

    ¿Qué hace exactamente –ignore-lock en astro preview?

    Se salta la comprobación del lockfile que Astro 7.2 añadió a astro preview, de modo que puedes tener varios servidores de preview del mismo proyecto corriendo a la vez en puertos distintos. El flag ya existía en astro dev desde Astro 7.1; la 7.3 lo lleva también a preview.

    ¿Por qué astro preview –ignore-lock me da error?

    Porque --ignore-lock no se puede combinar con --background ni con --force: las dos opciones dependen del lockfile, así que Astro lanza un error. Y cuando Astro detecta que el comando lo ejecuta un agente de IA, activa el modo background automáticamente, aunque tú no hayas pasado --background. Si te ocurre, desactiva ese automatismo con la variable de entorno ASTRO_PREVIEW_BACKGROUND=0 delante del comando.

    ¿Por qué existe ese lockfile si nadie lo pidió?

    Porque Astro 7 lo introdujo para que los agentes de IA no levantaran servidores duplicados del mismo proyecto sin darse cuenta. Es un default pensado para un ejecutor que no recuerda si ya arrancó el servidor hace diez minutos, y por eso convive mal con flujos donde tú quieres varios servidores a propósito.

    ¿Los servidores lanzados con –ignore-lock se gestionan con astro preview stop?

    No. Las notas oficiales avisan de que esas instancias corren de forma independiente y están pensadas para servidores rápidos y de usar y tirar, no para los que administras con astro preview stop o astro preview status. Si los arrancas a mano, los cierras a mano; dentro de Playwright se encarga el teardown del webServer.

    ¿Tengo que tocar mi image service custom para aprovechar el logger?

    Solo si quieres. El cambio es aditivo: el logger llega como argumento adicional en transform() y dentro del contexto de onRequest() en los cache providers, así que tu código actual sigue funcionando. Cambiar console.warn() por logger.warn() es lo que hace que tus avisos respeten el nivel de log configurado y el flag --silent.

    ¿Necesito llamar a finalize() si uso Hono en Cloudflare?

    No. El middleware @astrojs/cloudflare/hono aplica esas cabeceras automáticamente. finalize() está pensado para quien monta un worker entrypoint propio sobre astro/fetch y necesita aplicar a mano las cookies y los defaults de caché del CDN de Cloudflare.

    ¿En qué versión de @astrojs/cloudflare está finalize()?

    En @astrojs/cloudflare 14.3.0, publicada el 3 de septiembre de 2026 junto a Astro 7.3. El adapter se versiona aparte de astro: subir astro a 7.3 no actualiza el adapter, tienes que subir los dos paquetes.

    ¿Hay breaking changes al actualizar a Astro 7.3?

    No. Es una release menor de mantenimiento sobre la 7.2: un flag nuevo, un logger que se propaga a APIs de extensión y un helper añadido en @astrojs/cloudflare 14.3. La actualización del adapter de Cloudflare va aparte de la de astro, así que revisa que subes las dos si estás en ese escenario.


    Si prefieres ver este tipo de análisis en vídeo, con el proyecto delante, lo publico en el canal de YouTube de Dominicode.

    Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.

  • Starlight 0.42: menos JavaScript, menú móvil roto en silencio

    Starlight 0.42: menos JavaScript, menú móvil roto en silencio

    El viernes actualicé la documentación de un proyecto interno a Starlight 0.42. npx @astrojs/upgrade, build en verde, Lighthouse un punto mejor. Cerré el portátil.

    El lunes un compañero me pasa una captura desde el móvil. El menú abría perfecto. Pero el botón se quedaba gris. Nuestro color de marca al abrir el menú había desaparecido.

    Nada había fallado. Ese es el problema. El CSS no lanza errores: cuando un selector deja de coincidir con algo, se calla y sigue. El build no te avisa, los tests no lo ven y tú te enteras cuando alguien abre el sitio en un teléfono.

    El anuncio oficial de la release vende una paradoja simpática —menos JavaScript y más JavaScript a la vez— y para los detalles te remite al CHANGELOG. Este post es el CHANGELOG explicado, con el CSS concreto que tienes que cambiar.

    El titular es "menos JavaScript". La letra pequeña es que si tocaste el menú móvil con CSS o JS propio, la 0.42 te lo rompe sin decir nada.


    La paradoja de Starlight 0.42: "un 100 % más de JavaScript"

    El chiste es del propio anuncio y tiene truco. Hay dos JavaScript distintos aquí y el post oficial los mezcla a propósito.

    Uno es el JavaScript que va dentro del paquete de npm. Ese sube: Starlight ha dejado de publicar TypeScript y ahora distribuye JavaScript compilado.

    El otro es el JavaScript que llega al navegador de quien lee tu documentación. Ese baja: el menú móvil ya no necesita JS para funcionar.

    Build-time contra runtime. Son cosas distintas y confundirlas es el error clásico al leer notas de release. Con la 0.42 en la mano, un sitio Starlight medio sigue enviando entre 3 y 13 veces menos JavaScript al usuario final que herramientas comparables: MkDocs, Sphinx, VitePress, Nextra, GitBook o Docusaurus.

    Es la misma lógica que ya movía a Astro con las server islands: decidir con precisión qué se ejecuta en el servidor y qué viaja al cliente, en vez de mandarlo todo y confiar. Astro lleva varias releases insistiendo en lo mismo, desde que server islands y actions se estabilizaron en la 6.2.


    Por qué Starlight publicaba TypeScript y por qué ha parado

    Hay una rareza de los proyectos Astro que mucha gente no conoce: puedes publicar archivos .ts directamente en npm y funcionan cuando alguien los instala. Sin build step. Genial para prototipar rápido, y así se venía publicando Starlight desde el principio.

    El coste aparecía en tu proyecto, no en el suyo.

    Si haces typecheck con tsc, TypeScript revisa cualquier .ts que encuentre importado, incluso dentro de node_modules. Así que acababas comprobando el código fuente de Starlight. Y no con la configuración del paquete, sino con la tuya. En algunos casos el rendimiento de tipos en el editor también se resentía. En una base de código del tamaño de Starlight, esos problemas se acumulan.

    La 0.42 compila sus fuentes y distribuye JavaScript más archivos de declaración (.d.ts). El resultado esperable es un typecheck más rápido en tu máquina — y más aún cuando aterrice el compilador de TypeScript escrito en Go.

    Detalle que conviene tener claro: un .d.ts describe tipos en tiempo de compilación y desaparece en tiempo de ejecución. No valida nada.

    La validación de verdad ya la estás usando aunque no te hayas fijado: el frontmatter de tus páginas lo comprueba Starlight con esquemas de Zod durante el build. Y si tu sitio además tiene formularios o endpoints, ahí hace falta el mismo tipo de esquema pero ejecutándose en runtime. Tipos y validación resuelven problemas distintos, aunque la gente los meta en el mismo saco.


    La Popover API: por qué el menú móvil deja de necesitar tu JavaScript

    Aquí está el cambio de fondo.

    Antes, el menú móvil era una máquina de estados escrita a mano: un custom element <starlight-menu-button> que escuchaba clics, cambiaba aria-expanded en el botón y ponía un atributo en el <body>. Si el JavaScript no llegaba a ejecutarse, no había menú.

    Y hay más razones de las que la gente cree para que el JavaScript no se ejecute. La red se cae a medias. Otro script peta antes y se lleva por delante el resto del bundle. Una extensión del navegador se mete por medio. Alguien lo tiene desactivado. En un sitio de documentación —que muchas veces es la primera vez que alguien te ve— eso es una puerta cerrada.

    La 0.42 delega ese estado en la Popover API del navegador. El menú abre aunque tu JavaScript nunca llegue.

    Menos código propio, más primitiva nativa. Es la dirección correcta.

    Pero ojo con la consecuencia: si el estado ya no vive en un atributo del botón, tu CSS no tiene a qué agarrarse.


    Los 3 breaking changes de Starlight 0.42, en una tabla

    Starlight 0.42 rompe tres cosas y solo tres. Esta es la traducción directa de código viejo a código nuevo:

    Qué desaparece Reemplazo en 0.42 A quién afecta
    <starlight-menu-button> y aria-expanded .sl-menu-button y .sl-menu-button:has(~ :popover-open) Estilos, temas o component overrides que apuntaban al botón del menú móvil
    body[data-mobile-menu-expanded] body:has(sl-sidebar-pane:popover-open) CSS o JS propio que reaccionaba a la apertura del menú
    Opción tagline en astro.config Sin reemplazo: se borra Configs que la declararon (nunca hizo nada)

    Si ninguna de las tres filas aparece en tu código, la actualización es transparente. Si aparece alguna, las tres secciones siguientes son tuyas.


    Breaking change 1: el botón del menú móvil

    El botón ya no va envuelto en el custom element <starlight-menu-button> y ya no usa aria-expanded. Ahora apuntas al botón con la clase .sl-menu-button y lees el estado abierto con la pseudo-clase :popover-open.

    Así estaba tu CSS antes:

    /* Antes: Starlight 0.41 y anteriores */
    starlight-menu-button button {
      border-radius: 999px;
      background: var(--sl-color-gray-6);
    }
    
    starlight-menu-button[aria-expanded="true"] button {
      background: var(--dc-brand);
      color: var(--sl-color-white);
    }
    

    Y así queda en la 0.42:

    /* Después: Starlight 0.42 */
    .sl-menu-button {
      border-radius: 999px;
      background: var(--sl-color-gray-6);
    }
    
    /* El estado abierto lo expone el navegador en el panel, no en el botón.
       Seleccionas el botón que tiene un popover abierto como hermano. */
    .sl-menu-button:has(~ :popover-open) {
      background: var(--dc-brand);
      color: var(--sl-color-white);
    }
    

    Fíjate en lo que ha cambiado de verdad. No es un nombre de clase: es de quién es el estado.

    Antes el estado estaba en el botón, porque lo escribía JavaScript. Ahora está en el panel, porque lo gestiona el navegador. Por eso el selector nuevo tiene que ser relacional: :has() con ~ :popover-open significa "este botón, cuando un hermano posterior suyo está abierto".


    Breaking change 2: adiós a data-mobile-menu-expanded

    El atributo data-mobile-menu-expanded que Starlight añadía al <body> mientras el menú estaba abierto ya no existe. Si lo usabas para ocultar una barra flotante, bloquear el scroll o apagar una animación, ese bloque de CSS ha dejado de aplicarse.

    /* Antes */
    body[data-mobile-menu-expanded] .dc-cta-flotante {
      display: none;
    }
    
    /* Después */
    body:has(sl-sidebar-pane:popover-open) .dc-cta-flotante {
      display: none;
    }
    

    Si además tenías JavaScript propio reaccionando al menú, el cambio te ahorra código. Antes tocaba vigilar un atributo:

    // Antes: espiar el atributo que ponía Starlight
    const boton = document.querySelector('starlight-menu-button button');
    
    new MutationObserver(() => {
      const abierto = boton.getAttribute('aria-expanded') === 'true';
      document.body.classList.toggle('menu-abierto', abierto);
    }).observe(boton, { attributeFilter: ['aria-expanded'] });
    

    Ahora el navegador te lo cuenta él solo con un evento nativo:

    // Después: el panel es el popover y emite un evento toggle
    const panel = document.querySelector('sl-sidebar-pane[popover]');
    
    panel?.addEventListener('toggle', (event) => {
      const abierto = event.newState === 'open';
      document.body.classList.toggle('menu-abierto', abierto);
    });
    

    Un MutationObserver menos en tu sitio. Esa es la parte buena de apoyarse en primitivas del navegador: el código que borras no puede fallar.


    Breaking change 3: la opción tagline ya no existe

    Se elimina de la configuración. Nunca se llegó a usar para nada, así que no hay reemplazo: la borras de tu astro.config y listo. Si no la quitas, la validación de config te lo dirá.


    Requisitos mínimos y navegadores que se caen

    Starlight 0.42 exige Astro v7.2.10 o superior. Si usas @astrojs/markdown-satteri, necesitas 0.4.0 o superior. Si sigues con @astrojs/markdown-remark, 7.3.0 o superior.

    Si tu sitio todavía está en Astro v6, el salto grande no es este release, es el anterior: repasa primero las novedades de Astro v7 y hazlo en un PR aparte. Actualizar dos majors en el mismo commit es la forma más rápida de perder la tarde.

    Y hay una lista de navegadores que dejan de tener soporte oficial:

    Navegador Versión mínima soportada
    Chromium 116 (agosto de 2023)
    Safari 17.0 (septiembre de 2023)
    Firefox 125 (abril de 2024)

    No es un capricho, pero tampoco es el mínimo exacto de la API. Firefox 125 y Safari 17.0 son justo las versiones donde aterrizó la Popover API. En Chromium llegó antes, en la 114, así que ahí Starlight se ha guardado dos versiones de margen. Y en iPhone no hay sorpresa: el Safari de iOS la soporta desde la misma 17.0 que el de escritorio.

    El precio de apoyarse en el navegador es aceptar su calendario. Mira tus analíticas antes de decidir: en un sitio de documentación técnica, ese tráfico suele redondear a cero.


    Lo que mejora sin que hagas nada

    Dos cosas llegan gratis con la actualización.

    Rendimiento. La última versión de Sätteri —el motor de Markdown y MDX de Astro escrito en Rust, que llegó en Astro 6.4 y es el motor por defecto desde Astro 7— les ha permitido optimizar componentes y plugins de Markdown, y reducir el número de dependencias de Starlight. El procesado de datos del sidebar es ahora hasta 1.400 veces más rápido, y eso se nota de verdad en sitios con sidebars grandes o muy anidados.

    Ojo con un detalle que no es opcional. Sätteri no ejecuta plugins de remark ni de rehype: tiene su propio sistema de plugins mdast y hast, y no hay fallback automático.

    Y aquí no eliges tú. Como es el motor por defecto de Astro 7, y la 0.42 exige Astro v7.2.10 o superior, la actualización te lo puede cambiar sola. Si tu pipeline depende de remark o rehype, tienes que quedarte explícitamente en @astrojs/markdown-remark 7.3.0 o superior. Compruébalo antes de lanzar el upgrade, no después.

    Accesibilidad. El menú móvil atrapa el foco mientras está abierto, para que no puedas tabular hacia la página que queda escondida debajo. Detrás está el criterio de éxito WCAG 2.4.11, «Focus Not Obscured (Minimum)»: el elemento con el foco no puede quedar tapado por lo que hay encima. Se agradece en viewports pequeños o con mucho zoom. Llegó en la 0.41.3, así que si vienes de la última 0.41.x ya lo tienes. Si esto lo habías parcheado tú a mano, bórralo: ahora hay dos implementaciones peleándose por el foco.


    Cómo actualizar a Starlight 0.42 paso a paso

    1. Comprueba que estás en Astro v7. Starlight 0.42 exige Astro v7.2.10 o superior. Si vienes de Astro v6, haz ese salto antes y en un PR aparte.

    2. Busca lo que se va a romper. Cuatro grep antes de tocar nada:

      grep -rn "starlight-menu-button" src/
      grep -rn "data-mobile-menu-expanded" src/
      grep -rn "aria-expanded" src/styles/
      grep -rn "tagline" astro.config.*
      

      Cada resultado es una línea que hay que migrar. Si no aparece nada, actualiza tranquilo.

    3. Actualiza. Un solo comando sube Starlight, Astro y el resto de integraciones a la vez:

      npx @astrojs/upgrade
      
    4. Migra el CSS y el JS con la tabla de equivalencias de más arriba: .sl-menu-button, .sl-menu-button:has(~ :popover-open) y body:has(sl-sidebar-pane:popover-open).

    5. Abre el sitio en un móvil de verdad y toca el botón del menú. No en el simulador de Chrome: en un teléfono. Es el único sitio donde estos tres breaking changes se manifiestan.

    Este tipo de migración quirúrgica —buscar patrones muertos, cambiarlos y verificar— es exactamente lo que un agente hace bien si le das el CHANGELOG y los selectores concretos. Es el flujo que enseño en Construye con IA: contexto preciso primero, ejecución después.


    La conclusión que te llevas

    Un release que quita JavaScript casi siempre mueve el estado a otro sitio. Y el CSS que apuntaba al estado viejo no se queja: se apaga. Es el mismo patrón que en los breaking changes de pnpm 12: la nota de release vende el titular y el trabajo real está tres párrafos más abajo.

    Si mantienes un sitio con Starlight, haz hoy los cuatro grep de arriba antes de actualizar. Tardas menos de lo que has tardado en leer este post, y te ahorras la captura de un compañero el lunes por la mañana.

    En Dominicode Labs trabajamos este tipo de migraciones sobre proyectos reales, con el diff delante en vez de con el anuncio de marketing. Y el anuncio original, por si quieres la versión oficial, está en el blog de Astro.


    Preguntas frecuentes

    ¿Cómo actualizo a Starlight 0.42?

    Ejecuta npx @astrojs/upgrade, que sube Starlight, Astro y el resto de integraciones a la vez. Antes de lanzarlo, busca en tu proyecto starlight-menu-button, data-mobile-menu-expanded, aria-expanded en tus estilos y tagline en astro.config: cada coincidencia es una línea que hay que migrar. Necesitas Astro v7.2.10 o superior. Después, abre el sitio en un móvil real y comprueba el botón del menú.

    ¿Starlight 0.42 envía más o menos JavaScript al navegador?

    Menos. El "100 % más de JavaScript" del anuncio se refiere al paquete de npm, que ahora se distribuye compilado a JavaScript en lugar de TypeScript. Lo que llega al navegador de quien lee tu documentación baja, porque el menú móvil se apoya en la Popover API nativa en vez de en código propio. Un sitio Starlight medio sigue enviando entre 3 y 13 veces menos JavaScript al usuario final que MkDocs, Sphinx, VitePress, Nextra, GitBook o Docusaurus.

    ¿Por qué ha dejado de aplicarse mi CSS del menú móvil tras actualizar?

    Porque el botón ya no va envuelto en el custom element <starlight-menu-button> y ya no usa el atributo aria-expanded. Cualquier selector construido sobre esos dos elementos deja de coincidir con nada y el navegador lo ignora en silencio. La migración es apuntar al botón con .sl-menu-button y leer el estado abierto con .sl-menu-button:has(~ :popover-open).

    ¿Por qué el selector nuevo usa :has() en lugar de una clase en el botón?

    Porque el estado ha cambiado de dueño. Antes lo escribía JavaScript en el botón; ahora lo gestiona el navegador en el panel del menú, que es el elemento popover. Para estilar el botón según ese estado necesitas un selector relacional: :has(~ :popover-open) significa "este botón, cuando un hermano posterior suyo está abierto". Para el <body>, el equivalente del antiguo data-mobile-menu-expanded es body:has(sl-sidebar-pane:popover-open).

    ¿Qué versiones mínimas necesito para actualizar a Starlight 0.42?

    Astro v7.2.10 o superior. Si usas @astrojs/markdown-satteri, 0.4.0 o superior. Si usas @astrojs/markdown-remark, 7.3.0 o superior. El comando npx @astrojs/upgrade se encarga de subir Starlight, Astro y el resto de integraciones a la vez.

    ¿Debería preocuparme por los navegadores que pierden soporte?

    Depende de tus analíticas, pero casi nunca. Se cae el soporte oficial de Chromium anterior a la 116 (agosto de 2023), Safari anterior a 17.0 (septiembre de 2023) y Firefox anterior a 125. Son los mínimos que exige la Popover API. En documentación técnica ese tráfico suele ser residual; míralo antes de bloquear la actualización por si acaso.

    ¿Qué hago si tenía JavaScript propio escuchando la apertura del menú?

    Bórralo y escucha el evento nativo. El panel es el popover, así que un panel.addEventListener('toggle', ...) con event.newState === 'open' te da lo mismo que antes conseguías con un MutationObserver sobre aria-expanded, con la mitad de código y sin depender de detalles internos de Starlight.

    ¿Y la opción tagline de la configuración?

    Se ha eliminado y no tiene reemplazo, porque nunca se llegó a usar. Bórrala de tu astro.config al actualizar.


    Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.

  • Mejoras en Astro 6.2: Server Islands y Astro Actions

    Lo nuevo de Astro 6.2 y porque lo tienes que probar

    Tiempo estimado de lectura: 4 min

    • Rendimiento y entrega de HTML: Server Islands y mejoras que reducen el TTFB.
    • Ergonomía y seguridad: Astro Actions introduce RPC tipado con validación integrada.
    • Contenido externo en build: Content Layer trata APIs, CMS y bases como ciudadanos de primera clase.
    • Developer experience: arranques y HMR más rápidos en proyectos grandes o monorepos.

    Resumen y análisis técnico de las mejoras introducidas en Astro 6.2, con ejemplos prácticos y recomendaciones para equipos que priorizan rendimiento, tipado y manejo de contenido externo.

    Resumen rápido (lectores con prisa)

    Qué es: Actualización de Astro que mejora renderizado diferido, añade RPC tipado para mutaciones y consolida una capa de contenido para fuentes externas.

    Cuándo usarlo: Para sitios estáticos con zonas personalizadas, e-commerce y documentación donde SEO y Core Web Vitals importan.

    Por qué importa: Reduce JavaScript por defecto, mejora TTFB y convierte errores runtime en fallos de compilación mediante tipado.

    Cómo funciona (alto nivel): Server Islands difiere componentes dinámicos; Astro Actions expone funciones servidor/cliente tipadas; Content Layer mapea fuentes externas a colecciones validadas en build.

    Lo nuevo de Astro 6.2 y por qué lo tienes que probar: cambios clave

    Astro 6.2 no es una mejora cosmética. Afecta tres ejes que importan en producción: tiempo de entrega de HTML, seguridad y ergonomía del desarrollo, y cómo incorporas datos externos al proceso de build.

    • Mejoras en el servidor de desarrollo: resolución de módulos más rápida, arranques y HMR optimizados. Menos fricción en repos grandes o monorepos.
    • Server Islands estabilizadas: capacidad de diferir componentes server-side sin bloquear el TTFB.
    • Astro Actions: RPC tipado para mutaciones y formularios, con validación integrada.
    • Content Layer API: conectores para CMS, bases de datos o Notion, con validación y caching en build.

    Fuente oficial y changelog: astro.build/blog/astro-620/

    Server Islands: reducir TTFB sin perder personalización

    El patrón Server Islands en 6.2 se vuelve practicable en entornos de producción. La idea es simple y poderosa: renderizas la estructura estática y cacheable en el CDN; los componentes dinámicos se resuelven de forma diferida e independiente.

    Ejemplo mínimo

    ---
    import UserAvatar from '../components/UserAvatar.astro';
    ---
    
    Cargando avatar…

    Consecuencia práctica: el TTFB de la página no depende de la latencia de la consulta más lenta. Para páginas con contenido mayoritariamente estático y pequeñas zonas de personalización (e-commerce, landing pages personalizadas), la ganancia es directa y repetible.

    Documentación Server Islands: docs.astro.build/en/guides/server-islands/

    Astro Actions: menos endpoints, menos errores tipográficos

    Astro Actions introduce una abstracción RPC que reduce boilerplate y errores de sincronía entre cliente y servidor. Defines la acción en el servidor con validación (Zod) y la llamas desde el formulario como si fuera una función.

    Servidor

    import { defineAction } from 'astro:actions';
    import { z } from 'astro:schema';
    
    export const server = {
      subscribe: defineAction({
        input: z.object({ email: z.string().email() }),
        handler: async ({ email }) => {
          await db.insert({ email });
          return { success: true };
        },
      }),
    };
    

    Cliente (form)

    <form method="POST" action={actions.subscribe}>
      <input type="email" name="email" required />
      <button type="submit">Suscribirse</button>
    </form>
    

    Ventaja: si cambias el esquema, la compilación en el cliente falla. Eso convierte errores que antes aparecían en runtime en fallos de compilación, lo que mejora la confiabilidad y acelera el feedback loop.

    Guía de Actions: docs.astro.build/en/guides/actions/

    Content Layer API: datos externos como primera clase

    La Content Layer API en 6.2 permite tratar datos externos (CMS headless, Notion, bases SQL, APIs) como si fueran archivos locales durante el build. Tienes validación tipada, relaciones entre colecciones y caché inteligente.

    Arquitectónicamente significa desacoplar la fuente de contenido de la presentación sin perder seguridad en tipos y esquemas. Para equipos que manejan contenido editorial, marketing o documentación técnica, esto reduce fricción entre productores de contenido y desarrolladores.

    Docs Content Layer: docs.astro.build/en/guides/content-collections/

    ¿Cuándo adoptar Astro 6.2 y cuándo no?

    Adóptalo si:

    • Construyes sitios donde el SEO y Core Web Vitals son críticos (e-commerce, medios, docs).
    • Quieres reducir JavaScript enviado por defecto y solo hidratar lo necesario.
    • Necesitas un puente entre contenido diverso (Notion, CMS) y renderizado tipado en build.

    No es la mejor elección si:

    • Construyes aplicaciones con estado complejo y alta interactividad en cliente (editores colaborativos, apps en tiempo real intensivas).
    • Tu equipo necesita mantener un único modelo mental SPA sin fragmentar la responsabilidad entre server y client.

    Integración práctica: checklist rápido

    1. Prueba en un proyecto piloto: migra una página de marketing o un listado de productos.
    2. Instrumenta Server Islands en componentes con latencia (perfilado DB, llamadas externas).
    3. Usa Astro Actions en formularios y mutaciones sencillas para comprobar el feedback tipado.
    4. Conecta una fuente externa con Content Layer y valida el cacheo y el tiempo de build.
    5. Añade validaciones en CI para evitar regressiones en las APIs internas.

    Conclusión técnica

    Astro 6.2 madura un enfoque: menos JavaScript por defecto, más control en el servidor, y herramientas para que la mutación de datos y el contenido externo no sean fuentes de fragilidad. No es una panacea, pero sí una palanca técnica que reduce costes operativos y mejora métricas críticas. Pruébalo en un caso real y decide con datos, no con intuiciones. Repositorio y más referencias: github.com/withastro/astro

    FAQ

    ¿Qué mejora principalmente Astro 6.2?

    Mejora la entrega de HTML (TTFB), introduce RPC tipado para mutaciones (Astro Actions) y consolida una Content Layer para tratar fuentes externas con validación y cache en build.

    ¿Cómo reducen las Server Islands el TTFB?

    Separando el HTML estático (entregable y cacheable) de los componentes dinámicos que se hidratan o resuelven de forma diferida, la latencia de llamadas lentas no bloquea el primer byte retornado.

    ¿Qué son las Astro Actions y por qué usarlas?

    Son una abstracción RPC tipada que permite definir acciones en el servidor con validación y llamarlas desde formularios o cliente como si fueran funciones, reduciendo endpoints y errores de sincronía.

    ¿Qué tipos de fuentes puedo conectar con Content Layer?

    CMS headless, Notion, bases SQL y APIs; la Content Layer las trata como colecciones locales durante el build con validación tipada y caching inteligente.

    ¿Cuándo no es recomendable migrar a Astro 6.2?

    No es ideal para aplicaciones con estado complejo e interactividad intensa en cliente (por ejemplo editores colaborativos o apps en tiempo real que dependen de una mentalidad SPA única).

    ¿Dónde encuentro documentación y changelog?

    La nota de lanzamiento y el changelog están en astro.build/blog/astro-620/. La documentación de características específicas está en las guías: Server Islands, Actions y Content Collections en docs.astro.build.