Docs menu

Learning Logs · · 3 min read

Learning Astro: fast sites with zero JS by default

Astro from installation: .astro pages, components + scoped styles, islands architecture (client:load vs client:visible), and content collections for markdown blogs.

AstroIslandsMarkdown

Astro is the framework for sites with more content than interaction — landing pages, blogs, documentation, company profiles. Its principle is radical: zero JavaScript in the browser by default, and you “switch on” interactivity only in the components that need it (islands architecture).

1. Installation

Prerequisite: Node.js 20+.

npm create astro@latest my-site
# choose the "Empty" template to learn from scratch
cd my-site
npm run dev          # open http://localhost:4321

2. Pages = .astro files

Every file in src/pages/ automatically becomes a route (index.astro/, about.astro/about):

---
// Everything between these fences runs ON THE SERVER at build time — it never reaches the browser.
const products = await fetch("https://api.example.com/products").then(r => r.json());
const title = "My Shop";
---
<html lang="en">
  <body>
    <h1>{title}</h1>
    <ul>
      {products.map(p => <li>{p.name} — {p.price.toLocaleString()}</li>)}
    </ul>
  </body>
</html>

The syntax looks like JSX, but the output is pure HTML — that fetch happens at build time, not in your visitor’s browser.

3. Components & props

---
// src/components/Card.astro
const { title, price } = Astro.props;
---
<article class="card">
  <h3>{title}</h3>
  <p>{price.toLocaleString()}</p>
</article>

<style>
  /* automatically scoped — never leaks into other components */
  .card { border: 1px solid #e4e4e7; padding: 1rem; }
</style>
---
import Card from "../components/Card.astro";
---
<Card title="Gayo Coffee" price={85000} />

4. Islands: interactive only where needed

Need a genuinely interactive React/Vue/Svelte component? Mount it as an “island”:

npx astro add react
---
import Cart from "../components/Cart.jsx";
---
<h1>This page is 100% static HTML...</h1>
<Cart client:load />   <!-- ...except this one island -->

The client:* directive decides when its JavaScript loads:

  • client:load — immediately on page open
  • client:visible — only when the component enters the viewport (my most-used)
  • client:idle — when the browser is idle

Without the directive, even a React component renders to static HTML — zero JS shipped.

5. Managed markdown content (content collections)

Keep articles in src/content/blog/*.md, define their schema with Zod in src/content.config.ts, and Astro validates every article’s frontmatter at build time — a missing title = a failed build, not a silently broken page.

Tips from experience

  • Astro wins in the same cases as this site’s approach (Hono SSR + HTMX): content first, JavaScript later. Measure with Lighthouse and compare against an SPA yourself.
  • Start with client:visible, not client:load — most interactivity lives below the fold.
  • If every page needs per-request real-time data, Astro’s server mode (SSR adapter) works, but consider whether another framework fits better — Astro’s core strength remains fast static content.

Want something like this built for your business?