Astro is a full-stack JavaScript meta-framework that orchestrates reactive view technologies like React and Svelte. While there are numerous meta-frameworks (examples include Next.js and Remix), Astro is unique in uniting the features and components of a variety of reactive technologies in one powerful meta-environment.
Astro generates whatever static content it can on the server and isolates reactive components in islands. The static content is SEO-friendly and packaged without JavaScript, while the reactive components are also optimized to send only the necessary JavaScript code. The result is an optimized, orderly, best-of-both-worlds front end.
This article is a hands-on introduction to one of the most popular frameworks in the recent State of JavaScript survey. We’ll develop a simple application together and you’ll get a feel for the syncretic power Astro brings to the table.
Creating a new project in Astro
For our example, we’ll quickly bring together React and Svelte in an application built with Astro.
Astro’s command-line tool makes starting a new project a breeze:
$ npm create astro@latest astro-svelte-react
You can accept all the defaults in this case. (See the Astro docs for additional startup details.)
Now we move into the new directory and add React and Svelte as integrations:
$ npx astro add react
$ npx astro add svelte
You can see where these are added in astro.config.mjs
. Based on just these few steps, Astro has already created a landing page for us at src/pages/index.astro
. Run the app in development mode if you want to take a look:
$ npx astro dev
Now let’s start writing the application code. We’ll start with two simple components in React and Svelte. Astro lets us freely mix and match them in the components directory using their native file types.
First up is a Svelte counter component, which is located in the components
directory:
// src/components/SvelteCounter.svelte
Count: {count}
This is standard Svelte code. We have a script
element containing the JavaScript and then some markup with our view template, giving access to the variables and functions we’ve created in the script. This is a simple counter that increments a value when the button is clicked and displays it.
We can do the same thing with the React component:
// src/components/ReactCounter.jsx
import { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(0);
return (
Count: {count}
);
}
Here, we have a functional React component that holds one value in useState
and uses it to present a button in JSX, which increments the value when clicked. It has the exact same semantics as the Svelte component.
Updating the src/pages/index.astro
file ties the two components together:
---
import ReactCounter from '../components/ReactCounter.jsx';
import SvelteCounter from '../components/SvelteCounter.svelte';
---
Astro.js Demo Welcome to the InfoWorld Astro.js, Svelte, React Demo!
React Counter
Svelte Counter
Astro’s syntax uses ---
tokens (called script fences) to denote code sections, similar to Svelte’s code blocks. In this case, we import the two components you’ve just seen.
In the view template, which is straight HTML with access to components and code via special syntax extensions, we create a simple page. The key part for our purposes is the two component references:
If we now visit this page, we’ll see our components side by side. That might not seem terribly impressive but technologically, it’s a marvel. Svelte and React are two entirely different worlds, and yet Astro has brought them together seamlessly. The smoothness of the whole process, starting with the CLI integration, is really admirable.
Pluggable web development with Astro
You might wonder how all this is applicable in the real world. Well, imagine you’ve been using React but now you are falling in love with Svelte, or vice versa. You want to take your existing application and see about using that other framework. In this scenario, Astro’s ability to draw the existing components together becomes a superpower for evaluating, prototyping, and migrating applications.
What’s even more important, beyond the everyday applications, is Astro’s ability to encompass a variety of tools into a common system. In Astro’s universe, Svelte and React are treated like plugins, which means the web itself just became more pluggable.
Client directives
You might’ve noticed the client:load
attributes in the above code sample. These are directives to Astro, which you can use to fine-tune behavior in a variety of ways. In this case, the attribute is telling the engine when to “hydrate” the front end component, specifically here, upon page load. (Learn more about client directives here.)
Astro is at heart a server-side framework, so by default it strips out the JavaScript found in the code braces. If you really want to send the JavaScript, you can include a typical tag. In essence, Astro wants to render everything for you on the server and ship a streamlined, HTML-only package to the client.
Astro’s variable scope
When you need front-end interactivity, you can set it up like we’ve done using a Reactive framework or with vanilla JavaScript. Either way, Astro works on the server side. A good way to drive this point home is to look at Astro’s support for variables that can be inserted into the HTML templates. For example, we could create a starting value in index.astro
like so:
---
import ReactCounter from '../components/ReactCounter.jsx';
import SvelteCounter from '../components/SvelteCounter.svelte';
const startingValue = Math.floor(Math.random() * 100);
---
// …
This is on the server: {startingValue}
This displays the random value generated on the server on the client page. Remember, though, that it’s all done on the server. If we wanted to use this value on the client, we could pass it into the components as a parameter. For example, we could make the Svelte component accept a parameter like so:
Count: {count}
Notice the export let startingValue
syntax, which is Svelte-speak for exposing a pass-in parameter to its parent. To use this back on the index page you’d type:
You can do the same kind of thing with the React component:
// index.astro
// ReactCounter.jsx
import { useState } from 'react';
export default function Counter(props) {
const [count, setCount] = useState(props.startingValue);
return (
Count: {count}
);
}
React uses the first argument of the functional component to field incoming properties.
Astro’s simple arrangement has a lot of power up its sleeve. Let’s think about if we wanted to retrieve our startingValue
from a remote server. We could do this very simply while keeping it on the server:
---
import ReactCounter from '../components/ReactCounter.jsx';
import SvelteCounter from '../components/SvelteCounter.svelte';
const response = await fetch('https://www.random.org/integers/?num=1&min=0&max=100&col=1&base=10&format=plain');
const startingValue = await response.text();
---
This is on the server from a remote API: {startingValue}
Of course there’s nothing to prevent using a typical fetch statement inside the Svelte or React code to get the value from a client-side API call. In essence, we have a simple and direct way to say whether we want something to happen on the server or on the client, and we get to choose the syntax we’ll use on the client.
Conclusion
There’s a lot more to learn and appreciate about Astro, like its built-in support for Markdown and the lazy-loading and code-splitting possibilities you can get from client directives.
You might notice that Astro’s routing borrows from Next.js in providing default file-based routes. Astro has traditionally focused on generating pages, but it now supports endpoints too. The range of possibilities includes essentials like route slugs and parameters.
Astro started with a compelling idea and has continued to develop admirably. Its simplicity is well-encoded in both a stellar JavaScript web framework and an underlying philosophy worth watching. By abstracting the view technology, and making it swappable, Astro makes web development that much more pluggable. Initially, I was concerned Astro would be overly complex to use. But in practice, Astro simplifies things: it makes using view technologies like Svelte and React together an obvious and easy choice. That’s pretty remarkable when you think about it.