Islas, hidratación y scope en el output
Cómo el compilador traduce lo que escribes en el marcado del navegador: las directivas client como contrato que declara una isla, el elemento astro-island que envuelve cada componente hidratado con sus props serializadas y la URL de su renderizador, y el hash de ámbito data-astro-cid que aísla los estilos. Todo lo que el runtime hace en el cliente empieza como una decisión del compilador.
La directiva client como contrato
Cuando escribes un componente de framework con una directiva client:, no estás llamando a una función: estás firmando un contrato con el compilador. La directiva client:load, client:visible, client:idle o client:only es una anotación que el compilador detecta durante la transformación y que cambia por completo lo que emite para ese nodo. Sin directiva, el componente se renderiza en el servidor y se sirve como HTML muerto, sin un byte de JavaScript. Con directiva, el compilador lo marca como isla y planifica su hidratación.
---import Contador from '../components/Contador.jsx';---<Contador client:visible initial={3} />Esa sola palabra, client:visible, dispara tres decisiones en el compilador: registrar el componente en la lista de hydratedComponents que vimos en el pipeline, recordar qué estrategia de carga pediste —cargar al ser visible—, y envolver la salida en un elemento especial que el runtime sabrá reconocer. La directiva es, por tanto, el punto donde tu intención declarativa se traduce en un plan de hidratación. No hidratas tú; declaras que ese nodo quiere hidratarse, y el compilador prepara todo para que ocurra.
La misma línea de código produce dos salidas radicalmente distintas según lleve o no la directiva. El contraste se ve mejor en el HTML emitido en cada caso:
<!-- SIN directiva: HTML plano, cero JavaScript, no revive --><button>3</button><!-- CON client:visible: envuelto y listo para hidratarse --><astro-island component-url="..." client="visible" props="..."> <button>3</button></astro-island>Sin client:, el compilador renderiza el componente en el servidor y estampa su HTML plano, sin envoltorio ni referencia a ningún módulo de cliente. Con client:, ese mismo HTML aparece envuelto y acompañado de las rutas y las props que permitirán revivirlo. La directiva no cambia lo que el componente muestra; cambia si ese componente seguirá vivo en el navegador.
astro-island: el envoltorio en el HTML
La marca que el compilador estampa alrededor de una isla es un elemento personalizado, <astro-island>, y leerlo en el HTML final revela toda la mecánica. Ese elemento no lo escribes tú: lo genera el compilador para cada componente con directiva, y lleva en sus atributos todo lo que el runtime del cliente necesita para revivir el componente en el momento acordado.
<astro-island uid="Z1qs8x" component-url="/_astro/Contador.abc123.js" renderer-url="/_astro/client.react.def456.js" props='{"initial":{"type":"number","value":3}}' client="visible" ssr> <button>3</button></astro-island>Cada atributo es una pieza del rompecabezas, y conviene leerlos uno a uno porque juntos son el plan de hidratación completo:
uid: un identificador único de esta isla en la página, para que el runtime no confunda unas con otras.component-url: la ruta al módulo de tu componente ya empaquetado.renderer-url: la ruta al adaptador del framework —React, Vue, Svelte— que sabe hidratarlo.client: la estrategia grabada de la directiva; aquí,visible.props: tus props serializadas en un JSON con tipos.ssr: la señal de que el HTML de dentro se renderizó en el servidor.
Dentro del elemento va el HTML renderizado en el servidor, el que el visitante ve antes de que llegue ni un byte de JavaScript. El runtime lee estos atributos, importa las dos URLs cuando la estrategia lo indica y sustituye ese HTML por el componente vivo. Nada de eso lo decide el cliente por su cuenta: todo estaba escrito de antemano por el compilador en los atributos del envoltorio.
Fíjate en la economía del diseño: dos islas del mismo componente en una página comparten component-url y renderer-url —el navegador descarga cada módulo una sola vez— pero difieren en su uid y en sus props. El compilador no duplica código; duplica solo el contrato mínimo que distingue una instancia de otra. Por eso una página con veinte tarjetas interactivas no envía veinte copias del componente, sino una y veinte pequeños sobres de datos. La granularidad de la hidratación —qué se carga, cuándo y para qué instancia— está enteramente decidida en estos atributos que el compilador estampó.
El hash de ámbito para los estilos
La otra gran marca que el compilador estampa nace de los bloques <style>. Al ver estilos en un componente, calcula un hash determinista a partir de la identidad del archivo y lo usa para dos cosas a la vez: sella cada elemento de la plantilla con el atributo data-astro-cid-<hash> y reescribe cada selector del bloque para que exija esa misma marca. El estilo queda confinado no por una barrera, sino por una condición que solo se cumple dentro del componente.
<!-- lo que emite el compilador para un componente con estilos --><article class="tarjeta" data-astro-cid-hbhonbnp>Contenido</article><style>.tarjeta[data-astro-cid-hbhonbnp]{color:#7c3aed}</style>Que el hash sea determinista es deliberado: mientras la identidad del componente no cambie, la marca es idéntica entre builds, lo que estabiliza las hojas de estilo y favorece la caché. Este mecanismo tiene su nivel dedicado en la guía; lo que importa aquí es dónde nace: en el compilador, en el mismo tramo de transformación donde se marcan las islas.
Cómo se ancla esa marca en el selector no está grabado en piedra: el compilador obedece a la opción scopedStyleStrategy de la configuración, que decide si la condición se añade como selector de atributo, como clase o envuelta en :where para no sumar especificidad. Es un ejemplo perfecto de que el output no es fijo, sino el resultado de una política que tú puedes ajustar y que el compilador aplica de forma uniforme a cada componente.
Islas y scope resultan ser, en el fondo, la misma clase de operación: en ambos casos el compilador toma una intención que en tu .astro era implícita —este componente es interactivo, este estilo es local— y la convierte en una marca explícita en el HTML —un elemento <astro-island>, un atributo data-astro-cid— que otro programa leerá después. Son las dos huellas que el compilador deja en el output, y ambas son legibles a simple vista si sabes qué buscar.