[G1-Sync] Manual knowledge update
This commit is contained in:
@@ -0,0 +1,320 @@
|
||||
---
|
||||
id: frontend-astro-islands-deep
|
||||
title: Astro Islands — partial hydration architecture
|
||||
category: Coding
|
||||
status: draft
|
||||
source_trust_level: B
|
||||
verification_status: conceptual
|
||||
created_at: 2026-05-09
|
||||
updated_at: 2026-05-09
|
||||
tags: [frontend, astro, vibe-coding]
|
||||
tech_stack: { language: "TS", applicable_to: ["Frontend"] }
|
||||
applied_in: []
|
||||
aliases: [Astro, islands, partial hydration, MPA, content-driven, HTML-first]
|
||||
---
|
||||
|
||||
# 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
|
||||
```astro
|
||||
---
|
||||
// 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
|
||||
```astro
|
||||
<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
|
||||
```astro
|
||||
---
|
||||
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
|
||||
```ts
|
||||
// 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 };
|
||||
```
|
||||
|
||||
```astro
|
||||
---
|
||||
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
|
||||
```ts
|
||||
// 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
|
||||
```astro
|
||||
---
|
||||
import { ViewTransitions } from 'astro:transitions';
|
||||
---
|
||||
|
||||
<head>
|
||||
<ViewTransitions />
|
||||
</head>
|
||||
```
|
||||
|
||||
→ Page navigation 가 smooth.
|
||||
→ [[Web_View_Transitions_Cross_Doc]].
|
||||
|
||||
### Static generation (SSG default)
|
||||
```bash
|
||||
astro build
|
||||
# → dist/ (HTML files).
|
||||
```
|
||||
|
||||
### SSR (옵션)
|
||||
```ts
|
||||
// astro.config.mjs
|
||||
import vercel from '@astrojs/vercel/serverless';
|
||||
|
||||
export default {
|
||||
output: 'server',
|
||||
adapter: vercel(),
|
||||
};
|
||||
```
|
||||
|
||||
→ Per-route prerender option.
|
||||
|
||||
### Hybrid
|
||||
```astro
|
||||
---
|
||||
export const prerender = true; // page-level
|
||||
---
|
||||
```
|
||||
|
||||
→ 매 page 가 SSG / SSR 선택.
|
||||
|
||||
### Image optimization
|
||||
```astro
|
||||
---
|
||||
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
|
||||
```mdx
|
||||
---
|
||||
title: My Post
|
||||
---
|
||||
|
||||
import Counter from '../components/Counter';
|
||||
|
||||
# My Post
|
||||
|
||||
<Counter client:load />
|
||||
```
|
||||
|
||||
→ Markdown + JSX.
|
||||
|
||||
### Slot (component composition)
|
||||
```astro
|
||||
---
|
||||
// Layout.astro
|
||||
---
|
||||
<html>
|
||||
<body>
|
||||
<header><slot name='header' /></header>
|
||||
<main><slot /></main>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```astro
|
||||
---
|
||||
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
|
||||
```ts
|
||||
// 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.
|
||||
|
||||
## 🔗 관련 문서
|
||||
- [[Frontend_Astro_Patterns]]
|
||||
- [[Frontend_SolidJS_Qwik]]
|
||||
- [[Web_View_Transitions_Cross_Doc]]
|
||||
Reference in New Issue
Block a user