blog.dopana

Back

Astro là web framework cho content-first site. Khác với Next.js hay Nuxt — Astro ship zero JavaScript mặc định, chỉ thêm JS khi cần.

Next.js:  page → React → JS bundle → gửi JS cho client
Astro:    page → HTML → gửi HTML cho client (JS chỉ thêm nếu cần)
plaintext

Kết quả: site nhanh hơn, LightHouse 100/100 dễ hơn, ít JS hơn.

Islands Architecture#

Astro không hydrate toàn bộ trang. Nó chỉ hydrate các “island” — component React/Vue/Svelte riêng lẻ.

---
// src/pages/index.astro
import Header from '../components/Header.astro'
import LikeButton from '../components/LikeButton.tsx'
import Comments from '../components/Comments.svelte'
---

<!-- Static HTML — không JS -->
<Header />

<!-- Island — chỉ component này có JS -->
<LikeButton client:load />

<!-- Island khác — lazy hydrate khi scroll tới -->
<Comments client:visible />
astro

Client Directives#

<!-- Load JS ngay khi trang load -->
<Component client:load />

<!-- Load khi idle (cho component không critical) -->
<Component client:idle />

<!-- Load khi component visible trong viewport -->
<Component client:visible />

<!-- Load khi tương tác (click, hover) — cho modal/dropdown -->
<Component client:only="react" />

<!-- Tương tác media query -->
<Component client:media="(min-width: 768px)" />
astro

Mỗi island là một JS bundle riêng — không load React cho đến khi cần.

Zero JS Mặc Định#

Kết quả: HTML thuần. Không React runtime, không hydration, không JS bundle.

Content Collections#

Content Collections là cách quản lý Markdown/MDX content có schema validation.

// src/content.config.ts
import { defineCollection, z } from 'astro:content'

const blog = defineCollection({
  schema: z.object({
    title: z.string().max(60),
    description: z.string().max(160),
    publishDate: z.coerce.date(),
    tags: z.array(z.string()).default([]),
    draft: z.boolean().default(false),
  }),
})

export const collections = { blog }
typescript

View Transitions#

View Transitions cho phép chuyển trang mượt mà không cần SPA:

---
// src/layouts/Layout.astro
---

<html>
  <head>
    <!-- Bật View Transitions cho toàn site -->
    <meta name="view-transition" content="same-origin" />
  </head>
  <body>
    <slot />
  </body>
</html>
astro

Hoặc dùng component Astro:

---
import { ViewTransitions } from 'astro:transitions'
---

<html>
  <head>
    <ViewTransitions />
  </head>
</html>
astro

Custom Animation#

---
import { fade, slide } from 'astro:transitions'
---

<a href="/blog" transition:animate={slide}>Blog</a>

<div transition:animate={fade({ duration: '0.3s' })}>
  <slot />
</div>
astro

Không cần React Router, không JS bundle. Trình duyệt xử lý animation native.

Server Islands#

Astro cho phép render component dynamic trên server — không gửi JS cho client:

---
// Component render ở server, cache riêng
import Dashboard from '../components/Dashboard.astro'
---

<Layout>
  <Dashboard server:defer />
  <!-- Component render trên server, stream HTML khi sẵn sàng -->
</Layout>
astro

Dùng cho: dữ liệu user-specific, API call nặng, cache riêng biệt.

Image Optimization#

---
import { Image } from 'astro:assets'
import hero from '../images/hero.png'
---

<!-- Tự động resize, format AVIF/WebP, lazy load -->
<Image
  src={hero}
  alt="Hero image"
  widths={[400, 800, 1200]}
  sizes="(max-width: 800px) 100vw, 800px"
  loading="lazy"
  decoding="async"
/>
astro

Astro tự động tối ưu: resize, format, responsive srcset.

Integrations#

Astro hỗ trợ UI framework phổ biến qua integrations:

npx astro add react # React
npx astro add vue # Vue
npx astro add svelte # Svelte
npx astro add solid # SolidJS
npx astro add tailwind # Tailwind CSS
npx astro add mdx # MDX support
npx astro add vercel # Vercel adapter
npx astro add sitemap # Sitemap
npx astro add partytown # Web Workers
bash

Build Output#

Static Site (Mặc định)#

npm run build
# dist/ — HTML, CSS, JS tĩnh
# Deploy lên Netlify, Vercel, Cloudflare Pages, S3...
bash

Server-Side Rendering#

// astro.config.ts
import vercel from '@astrojs/vercel/serverless'

export default defineConfig({
  output: 'server',
  adapter: vercel(),
})
typescript
# dist/server/ — server entry point
# API routes + dynamic pages render on request
bash

Hybrid#

// astro.config.ts
export default defineConfig({
  output: 'hybrid',  // Mặc định static, opt-in server
})
typescript
---
// pages/dashboard.astro — render trên server
export const prerender = false
---
astro

Astro vs Next.js#

Next.jsAstro
JS mặc địnhReact runtime (~40KB)Zero JS
RenderingSSG/SSR/ISRStatic/SSR/Hybrid
UI frameworkReact (Next)React/Vue/Svelte/Solid (tuỳ chọn)
ContentFile system hoặc CMSContent Collections
Imagenext/imageastro:assets
RoutingFile-based + App RouterFile-based
API routes✅ (server mode)
View Transitions❌ (cần thư viện)✅ Built-in
Islands❌ (hydrate whole page)✅ Islands Architecture

Chọn Next.js khi:#

  • Web app phức tạp, cần nhiều client interaction
  • Dashboard với real-time data
  • Cần API routes phía backend
  • Team quen React ecosystem

Chọn Astro khi:#

  • Content site (blog, docs, landing page)
  • E-commerce product pages
  • Portfolio, marketing site
  • Site cần load nhanh, SEO tốt
  • Muốn dùng nhiều UI framework cùng lúc

Tổng Kết#

Astro sinh ra từ một insight đơn giản: hầu hết web là content, không phải app.

---
// Blog này chạy Astro — zero JS cho content, island cho interactive parts
const posts = await getCollection('blog')
---

{posts.map(post => (
  <article>
    <h2>{post.data.title}</h2>
    <p>{post.data.description}</p>
  </article>
))}

<!-- Only interactive part gets JS -->
<LikeButton client:visible />
astro
Tính năngAstro
Zero JS mặc định
Islands Architecture
Content Collections✅ Schema, type-safe
View Transitions✅ Built-in
Server Islands
Image optimization
Multi-framework (React/Vue/Svelte)
Static + SSR + Hybrid
Bundle sizeTrang này ~0KB JS

Nếu site bạn là content-first — blog, docs, marketing, landing page — Astro là lựa chọn tốt nhất hiện tại.

Tài liệu tham khảo#