Our beloved frameworks like React.js, Angular, and Vue.js have one small problem: client-side rendering of HTML through JavaScript is very costly — on top of that, it's said to be SEO-unfriendly.
Static site generators provide a remedy. When building the production version, they render as much as possible directly into HTML, which is then available statically.
It is important to understand that the framework and all its features, such as hooks in React, are still included. Static site generators (from now on, just "SSGs") render the facade of our site. A lot of JS code is still included.
This is where Astro comes in, with one goal: as little JavaScript as possible. In fact, none at all by default. But first things first.
Astro is actually just an SSG. But we can use it with different frameworks — unlike VuePress or Gatsby it is not locked to one framework.
We build our site with UI components from a framework/library of our choice — React, Vue, or Svelte, it doesn't matter. Astro will then build the production version as a static page that has no JavaScript at all. Doing away with client-side rendering and hundreds of kilobytes of framework code has an extremely positive effect on the performance of the site.
But can a useful app exist without any JavaScript?
Of course not. Even for a network request, some animations, or more complex forms, we need JavaScript. This is where it gets really interesting: if a component needs JS, Astro loads the necessary code and its dependencies — but no more than that. This means that only as little JS as necessary is loaded, and the page remains fast.
Hyped enough? Let's try it out!
Getting started with Astro
Getting started is easy. Let's create a new project:
First, create a new, empty directory for the project. Then, run
npm init astro Select the "Starter Kit." As the framework/library, I am going to use React.js — so make sure to select React with pressing space and then enter.
Finally, run npm install.
Understanding the file structure
The only important directory, for now, is the "src" directory. Within, you should see the "components" and "pages" directory.
The pages folder is similar to Next.js or Gatsby for the individual pages of the app. Each of these pages has its own URL based on the file name, so index.astrois for the home page "/".
There are two files within the "components" directory — one is a typical JSX file for a React.js component. The other one is a static component, with the ending ".astro". It serves to split up HTML code and handle it as a component that can be imported on the pages. If you wish, you can write JavaScript code within the .astro files — simply use a script-tag.
But keep in mind, this JS will be shipped to the front end. In case you want to write JS code, there is a way aligned with Astro's philosophy. Maybe you noticed the weird dashes on top of the .astro files, like this:
---
---Every JS code you write within these lines is executed while building but not shipped to the final bundle. So, for example, the following code:
---
console.log("hello world")
---
<h1>A new component</h1>will log "hello world" in the terminal, but not in the browser. The JS code is not shipped and executed in the browser. It reminds me of the GraphQL queries one can write in Gatsby.
But why would we even write JS code, which is not executed in the browser? Well, to build up our static page. Imagine you want to host a static blog. You could fetch the content from your blog's API within the dashes and render it to a static page, thanks to Astro. In the end, you only ship a static page, and if your blog server only runs on your machine, even secure your blog.
But let's not leave it in theory — here is an example.
First, create a new .astro file in the components folder. I'll name it Operation.astro. Then, fill it with the following code:
---
function add(a, b) {
return a + b
}
---
<p>The result is:</p>
<p>{add(2,2)}</p>Now, go into the index.astro within the pages folder, and import our component:
import Operation from "../components/Operation.astro"Finally, we can render it somewhere on the page with <Operation />. When you run npm start and open up the page, you'll see "4", and that the calculation wasn't done in the browser:

I think you get the point. Let's learn more about Astro and how it handles components!
Hydration of components
When you scroll down in the default index.astro, you see a React component is rendered:
<ReactCounter client:visible />The component hides in src/components and is a basic counter, using a React hook. Of course, this needs JavaScript — so when you run npm run build and open the production version (you can do this with serve -s dist/ , after npm install -g serve) you see a working, React.js counter component.
In the network tab, we see this depends on JS, which is loaded:

The reason is simple: We said so.
The client:visible means that the components should load the necessary JS code once it is visible to the user — lazy loading, basically.
If you want to see it in action, reload the page, but keep the counter out of sight. When you open the Network tab and then scroll down until you drag the counter, JS code is dynamically loaded.
Pretty cool, right?
Apart from client:visible there are many more options for loading the JS part of our components. If you only render <ReactCounter /> in the index.astro file, the whole JS code is cut out — and it will never be loaded.
Therefore, the counter is visible on the page but does not work when we press the buttons. Yet, a helpful feature if you only have a static component.
If you want to learn more about hydrating components, make sure to check out the official doc — it is well explained.
Thank you for reading!
If you want to read more about frameworks:
More content at plainenglish.io