Astro

Most JavaScript frameworks render entire websites as large JavaScript applications. This approach, while simple, can leads to performance issues. Astro offers a solution with its Island Architecture.

Astro builds websites by breaking them into independent, encapsulated "islands" of functionality. Each island can be a single component, a group of components, or an entire page. Astro uses partial hydration, loading only the necessary JavaScript for each interactive island, resulting in faster page loads.

Getting Started with Astro

To create a new Astro project:

npm create astro@latest

This generates the following project structure:

├── README.md
├── astro.config.mjs
├── "package-lock.json"
├── package.json
├── public
│   └── favicon.svg
├── src
│   ├── components
│   │   └── Card.astro
│   ├── env.d.ts
│   ├── layouts
│   │   └── Layout.astro
│   └── pages
│       └── index.astro
└── tsconfig.json

Templates

Astro templates use the .astro file extension. Install the Astro extension for Visual Studio Code for enhanced language support.

Astro templates consist of two parts:

  1. Variables: Defined between --- delimiters.
  2. HTML Markup: The rest is HTML markup, this includes <style> and <script> tags.
---
const items = ["Dog", "Cat", "Platypus"];
---
<ul>
  {items.map((item) => (<li>{item}</li>))}
</ul>

Islands

Components are rendered as static HTML by default, no JavaScript is sent to the client unless explicitly requested. To make a component interactive, use the client directive:

<MyReactComponent client:load />

There are more options for the client directive:

  • client:idle load and hydrate component when browsers becomes idle, it has a lower priority as client:load.
  • client:visible load and hydrate component when it enters the viewport

Routing

Astro uses file-based routing, similar to Next.js:

/          -> src/pages/index.astro
/about     -> src/pages/about.astro

Dynamic Routing

/product/1 -> src/pages/product/[product].astro
/product/2 -> src/pages/product/[product].astro

To use dynamic routing, set the output option in astro.config.mjs to 'server' or 'hybrid':

export default defineConfig({
  output: 'server',
})

In src/pages/product/[product].astro, parameters can be accessed via Astro.params:

---
const { product } = Astro.params
---
<div>{ product }</div>

Visiting http://localhost:4321/product/99 should give you "99".

APIs

Requests can also be mapped to a .ts or .js file, in this case the file acts as an API controller.

For Example:

/resource -> src/pages/resource.ts
export async function GET({params, request}) {
  return new Response(JSON.stringify({ok: true}))
}

Accessing http://localhost:4321/resource should return {"ok":true}.

Markdown Support

Another interesting feature of Astro is it's built-in Markdown support, which makes it ideal for a lightweight CMS.

For example:

/about -> src/pages/about.md