Javascript cliente en Astro

Javascript que se ejecuta en navegador, no en local


Como hemos visto en artículos anteriores, Astro es un metaframework que prioriza el contenido HTML, con el objetivo de que este contenido se envíe al usuario ya construido y por lo tanto, la carga de páginas sea muy rápida.

Aunque esto sea así, no significa que esté prohibido o no podamos usar Javascript en nuestras páginas. Simplemente se nos recomienda intentar evitar añadir Javascript en el cliente salvo que sea absolutamente necesario, de modo que nos enfoquemos en una buena y rápida experiencia de usuario.

Javascript en Astro

Hemos hablado que Astro permite escribir código Javascript en la parte superior del frontmatter del fichero .astro, justo entre los fragmentos ---. Sin embargo, hay que tener bien claro que ese Javascript se ejecuta en local, no en el navegador. Es decir, es código Javascript de node y no código Javascript del navegador (Javascript cliente).

Esto puede servirnos para muchas tareas que no son necesarias en el navegador. Sin embargo, si queremos realizar operaciones Javascript en el navegador, necesitaremos sí o sí Javascript cliente. En ese caso, simplemente tenemos que añadir un bloque <script> con el contenido Javascript cliente deseado en nuestro componente .astro.

Veamos un ejemplo:

---
const title = "Mi componente Javascript";
---
<div class="menu-container">
  <h1>{title}</h1>
  <button>Click me!</button>
</div>

<script>
  const container = document.querySelector(".menu-container");

  const button = container.querySelector("button");
  button.addEventListener("click", () => {
    alert("Hello!!");
  });
</script>
Cuidado, scope global

Ten mucho cuidado si utilizas Javascript nativo para trabajar con el DOM en Astro. El código Javascript no hace scope el DOM, por lo que si no colocas los nombres de clase o ID correctos, puede que selecciones otro elemento global con el mismo nombre.

Como veremos más adelante, al usar <script> Astro procesa el código Javascript de su interior. Esto lo hace ideal para crear código Javascript en los componentes implicados, de modo que sea fácil de localizar la funcionalidad en los componentes a los que afecta. Sin embargo, sigue funcionando de forma global. Si te interesa una encapsulación real echa un vistazo al artículo de WebComponents en Astro.

Nuestra variable title se está creando en nuestro sistema local donde desarrollamos, sin embargo, el código Javascript dentro del <script> es código Javascript cliente que será ejecutado en el navegador. Sin embargo, hay un pequeño matiz importante: este código Javascript es procesado por Astro antes de llegar al navegador.

Astro leerá los bloques <script> que encuentre en el componente y realizará varias tareas:

  • 1️⃣ Procesará los import realizados, creando un «bundle» con todo.
  • 2️⃣ Permitirá acceder a paquetes de node_modules/ instalados con npm.
  • 3️⃣ Los scripts procesados se volverán a inyectar en el mismo lugar, pero con type="module".
  • 4️⃣ Se recomienda colocarlos en la ruta src/scripts (o similar).
  • 5️⃣ Si se usa un mismo componente en varios lugares, el script sólo se inyectará una vez.

Esta forma de crear código Javascript es muy interesante, por lo que se convierte en la primera opción para crear nuestro código Javascript de cliente.

Javascript con is:inline

Ahora veamos una pequeña modificación que podemos realizar al código anterior. Al crear nuestro bloque <script> vamos a añadirle un atributo is:inline:

<script is:inline>
  ...
</script>

Esto indicará que ese bloque Javascript no debe ser procesado por Astro, sino que se insertará literalmente en el navegador. Al hacerse directamente en navegador, esto proporciona algunas diferencias con la forma anterior:

  • 1️⃣ Los import locales a scripts de src/scripts no funcionarán.
  • 2️⃣ Los import a paquetes de node_modules no funcionarán.
  • 3️⃣ Los import a scripts public/ o a CDN si funcionarán (si usas type="module").
  • 4️⃣ Si se usa un mismo componente en varios lugares, el script se repetirá.

Utiliza el is:inline sólo cuando no te interese importar otros archivos, o sean archivos de public/ o un CDN que quieres que se importen literalmente, sin hacer ningún cambio.

Cuidado, al utilizar define:vars en un <script> se añade el is:inline automáticamente, por lo que no podrás usar import de node_module, por ejemplo.

Soporte de import en Astro

Si no te ha quedado claro cuando puedes usar un import en Astro, aquí va una tabla de resumen, donde puede verse con un mejor nivel de detalle:

-<script><script is:inline><script type="module">
import "../src/scripts/file.js"❌2️⃣❌3️⃣
import "/file.js" (public)❌1️⃣❌2️⃣
import("../src/scripts/file.js")❌3️⃣❌3️⃣
import("/file.js") (public)❌1️⃣
import "https://..." (CDN)❌2️⃣
import("https://...") (CDN)
  • 1️⃣ No se puede importar. Prueba a usar un <script src>.
  • 2️⃣ No se puede importar en un script sin type="module".
  • 3️⃣ En el navegador no se puede acceder a ese fichero.

¿Quién soy yo?

Soy Manz, vivo en Tenerife (España) y soy streamer partner en Twitch y profesor. Me apasiona el universo de la programación web, el diseño y desarrollo web y la tecnología en general. Aunque soy full-stack, mi pasión es el front-end, la terminal y crear cosas divertidas y locas.

Puedes encontrar más sobre mi en Manz.dev