5.7 KiB
5.7 KiB
id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
| id | title | category | status | source_trust_level | verification_status | created_at | updated_at | tags | tech_stack | applied_in | aliases | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| frontend-astro-islands-deep | Astro Islands — partial hydration architecture | Coding | draft | B | conceptual | 2026-05-09 | 2026-05-09 |
|
|
|
Astro Islands
"HTML-first, JS-on-demand". Static HTML + interactive island 만 hydrate. Content site / marketing 친화. Multi-framework.
📖 핵심 개념
- Default = static HTML.
client:*directive 가 island.- React / Vue / Svelte / Solid 동시.
- MPA 식 navigation.
💻 코드 패턴
File-based route
src/pages/
├── index.astro
├── about.astro
└── posts/
└── [slug].astro
Component
---
// src/pages/index.astro
import Counter from '../components/Counter.tsx';
const data = await fetch('/api/posts').then(r => r.json());
---
<html>
<body>
<h1>Posts ({data.length})</h1>
<Counter client:load />
<ul>
{data.map(p => <li>{p.title}</li>)}
</ul>
</body>
</html>
→ Frontmatter (---) = server. Body = HTML + island.
Hydration directive
<Counter client:load /> // 즉시
<Counter client:idle /> // requestIdleCallback
<Counter client:visible /> // intersection observer
<Counter client:media='(min-width: 768px)' />
<Counter client:only='react' /> // server render X
→ Per-island lazy.
Multi-framework
---
import ReactCounter from './ReactCounter.tsx';
import VueCounter from './VueCounter.vue';
import SvelteCounter from './SvelteCounter.svelte';
---
<ReactCounter client:load />
<VueCounter client:visible />
<SvelteCounter client:idle />
→ 같은 page 가 여러 framework. Migration 친화.
Content collection
// src/content/config.ts
import { defineCollection, z } from 'astro:content';
const blog = defineCollection({
schema: z.object({
title: z.string(),
date: z.date(),
tags: z.array(z.string()),
}),
});
export const collections = { blog };
---
import { getCollection } from 'astro:content';
const posts = await getCollection('blog');
---
{posts.map(p => <a href={`/blog/${p.slug}`}>{p.data.title}</a>)}
→ Markdown / MDX 가 type-safe.
Server endpoint
// src/pages/api/users.ts
import type { APIRoute } from 'astro';
export const GET: APIRoute = async () => {
const users = await db.users.findMany();
return new Response(JSON.stringify(users));
};
View Transitions
---
import { ViewTransitions } from 'astro:transitions';
---
<head>
<ViewTransitions />
</head>
→ Page navigation 가 smooth. → Web_View_Transitions_Cross_Doc.
Static generation (SSG default)
astro build
# → dist/ (HTML files).
SSR (옵션)
// astro.config.mjs
import vercel from '@astrojs/vercel/serverless';
export default {
output: 'server',
adapter: vercel(),
};
→ Per-route prerender option.
Hybrid
---
export const prerender = true; // page-level
---
→ 매 page 가 SSG / SSR 선택.
Image optimization
---
import { Image } from 'astro:assets';
import myImage from '../images/hero.png';
---
<Image src={myImage} alt='Hero' />
→ 자동 resize / format / lazy.
Performance
- 0 JS by default.
- 매 island 가 own bundle.
- Streamed HTML.
→ Lighthouse 100.
Use case
✓ Marketing site
✓ Blog / docs
✓ E-commerce (Shopify Hydrogen alternative)
✓ Portfolio
✓ Landing page
✗ 큰 SPA (Next 가 더 좋음).
✗ Dashboard (interactive heavy).
vs Next.js
Next.js:
- React-first.
- App Router (RSC).
- Vercel 친화.
- 큰 ecosystem.
Astro:
- Multi-framework.
- HTML-first (less JS).
- 작은 bundle.
- Content-driven.
→ 정적 / content = Astro.
큰 app = Next.
vs Eleventy
Eleventy: SSG only, JS island 없음.
Astro: SSG + island.
→ Astro 가 modern.
MDX
---
title: My Post
---
import Counter from '../components/Counter';
# My Post
<Counter client:load />
→ Markdown + JSX.
Slot (component composition)
---
// Layout.astro
---
<html>
<body>
<header><slot name='header' /></header>
<main><slot /></main>
</body>
</html>
---
import Layout from '../layouts/Layout.astro';
---
<Layout>
<h1 slot='header'>Title</h1>
<p>Content</p>
</Layout>
Production deploy
Vercel, Netlify, Cloudflare Pages.
- SSG: free / cheap.
- SSR: serverless.
→ 빠른, scalable.
Astro DB
// astro:db
import { db, eq, Comment } from 'astro:db';
const comments = await db.select().from(Comment).where(eq(Comment.postId, postId));
→ Built-in DB (Astro 5+, Turso 기반).
Real-world
- Astro docs (자체).
- Lit docs.
- Microsoft Bun docs.
- Cloudflare docs.
- The Guardian (일부).
LLM 친화
Markdown / MDX 가 native.
- AI 가 작성한 content 가 즉시.
- Component 가 자동 type-check.
🤔 의사결정 기준
| 상황 | 추천 |
|---|---|
| Marketing site | Astro |
| Blog / docs | Astro |
| 큰 SPA | Next.js |
| E-commerce static | Astro |
| 큰 dynamic | Next / Remix |
| Multi-framework migration | Astro |
❌ 안티패턴
- 모든 거 client:load: JS 폭발.
- Server-only logic 가 client: leak.
- No View Transitions: jarring nav.
- Big island: bundle 폭발.
- Mix framework 가 의도 없음: bundle 폭발.
🤖 LLM 활용 힌트
- Astro = HTML-first + island.
- Multi-framework + content collection.
- View Transitions native.
- 정적 / content site 의 default.