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 connpm
. - 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 desrc/scripts
no funcionarán. - 2️⃣ Los
import
a paquetes denode_modules
no funcionarán. - 3️⃣ Los
import
a scriptspublic/
o a CDN si funcionarán (si usastype="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 elis:inline
automáticamente, por lo que no podrás usarimport
denode_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.