Astro is a web framework that I like for a lot of reasons, but in particular I like that it runs as little JavaScript as possible (at runtime) by default. When I say "at runtime" I mean as the page is run in the browser, not when your site is built (I'm not going to get into the difference in this post as much, but you'll see why it matters in a sec).
Anyway, the lack of JavaScript at runtime makes for some really quick, lightweight sites that have a lot of power behind them, but sometimes you want to use some good ol' scripts.
An Astro component has some frontmatter at the top, kind of like Markdown, where you can import different components and scripts, and then a JSX-like syntax below:
// index.astro
---
import BaseLayout from "./BaseLayout.astro";
let userName = "pretend I'm calling a function or something here";
---
<BaseLayout>
<h1>Hello, {userName ? userName : "world"}!</h1>
</BaseLayout>
When you want to run a script on this page, you could import a component, or just add some <script>
tags to handle it.
But, what if you want to import an API?
// index.astro
---
import BaseLayout from "./BaseLayout.astro";
let userName = "pretend I'm calling a function or something here";
import api from "whatever";
---
<script>
const res = await api(); // api is not defined
</script>
<BaseLayout>
<h1>Hello, {userName ? userName : "world"}!</h1>
</BaseLayout>
Unfortunately, this won't work! Because the frontmatter imports and the script is called at different points, the api
function there is considered undefined
when you call it.
But, have no fear, this is actually a really quick fix:
// index.astro
---
import BaseLayout from "./BaseLayout.astro";
let userName = "pretend I'm calling a function or something here";
---
<script>
import api from "whatever";
const res = await api(); // api IS defined!
</script>
<BaseLayout>
<h1>Hello, {userName ? userName : "world"}!</h1>
</BaseLayout>
You just have to import your API at the <script>
level, and you're golden!
Did I write an entire blog post for a one-line fix? Yes.
I keep forgetting this is a thing and I figure a blog will help me actually remember this when I inevitably run into it again. Classic.
Happy trails!
Top comments (7)
But what happens, if you want your script to run across multiple components? What about persistence of state, if you have multiple scripts running that way?
It depends on how you want to organize your components! The Astro team recommends using Nano Stores for that.
Here is an example of Nano Stores - github.com/kamal250/hcg-levels/blo... while I was playing with Astro.
Nice tip!
I built findcool.tools with Astro.
Pretty nice experience
Just for better understanding. Assume, you run a script on the initial page that defines a variable, let say:
would this value be available in other modules?
So I have an API that takes care of all my database logic. I have been using PHP to communicate with that API and then server side render my pages. I just started using Astro and was about to start working on this part. Are you able to respond as to why the JavaScript does not go in the frontmatter but after it?
JavaScript can go in the frontmatter, but that JS is run at build time/server side. Any JS that is in a script outside of the frontmatter is run client side!