Astro Islands 아키텍처 완전 가이드 | 부분 Hydration으로 성능 극대화
이 글의 핵심
Astro의 혁신적인 Islands 아키텍처. 기본적으로 0 JavaScript를 전송하고, 필요한 컴포넌트만 선택적으로 Hydration합니다. React·Vue·Svelte를 한 페이지에서 동시에 사용할 수 있으며, Core Web Vitals를 크게 개선합니다.
이 글의 핵심
Astro Islands 아키텍처는 기본적으로 0 JavaScript를 전송하고, 필요한 컴포넌트만 선택적으로 Hydration합니다. React·Vue·Svelte를 동시에 사용할 수 있으며, 초기 JavaScript 크기를 90% 감소시켜 Core Web Vitals를 크게 개선합니다.
목차
Islands 아키텍처란?
Islands 아키텍처는 2019년 Katie Sylor-Miller가 제안한 부분 Hydration 패턴입니다.
🚀 핵심 개념
기존 SSR (Next.js, Nuxt)
서버:
- 전체 앱 HTML 생성
클라이언트:
- HTML 수신
- 전체 JavaScript 다운로드 (100KB+)
- 전체 앱 Hydration (500ms+)
→ 정적 콘텐츠도 Hydration (낭비!)
Islands 아키텍처 (Astro)
서버:
- HTML 생성
클라이언트:
- HTML 수신
- 인터랙티브 컴포넌트만 JavaScript 다운로드 (10KB)
- 해당 컴포넌트만 Hydration (50ms)
→ 정적 콘텐츠는 HTML만 유지
💡 Islands 비유
┌─────────────────────────────────┐
│ │
│ 정적 HTML (바다) │
│ │
│ ┌──────┐ ┌──────┐ │
│ │React │ │ Vue │ │ ← Islands (인터랙티브)
│ │Counter│ │Chart │ │
│ └──────┘ └──────┘ │
│ │
│ 정적 HTML (바다) │
└─────────────────────────────────┘
Astro 시작하기
프로젝트 생성
# Astro 프로젝트 생성
npm create astro@latest my-astro-project
# 옵션 선택:
# - Template: Empty
# - Install dependencies: Yes
# - TypeScript: Yes (Strict)
cd my-astro-project
npm run dev
React 통합
# React 추가
npx astro add react
# 또는 수동 설치
npm install @astrojs/react
npm install react react-dom
// astro.config.mjs
import { defineConfig } from 'astro/config';
import react from '@astrojs/react';
export default defineConfig({
integrations: [react()],
});
Islands 사용법
기본 예제
---
// src/pages/index.astro
import Layout from '../layouts/Layout.astro';
import Counter from '../components/Counter.tsx';
---
<Layout title="Islands Demo">
<h1>Welcome to Astro Islands</h1>
<!-- 정적 HTML (JavaScript 없음) -->
<p>This is static content with no JavaScript.</p>
<!-- Island: 클라이언트에서 Hydration -->
<Counter client:load />
<!-- 다시 정적 HTML -->
<p>More static content...</p>
</Layout>
// src/components/Counter.tsx
import { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
);
}
Client Directives (Hydration 전략)
1. client:load (즉시 로드)
<!-- 페이지 로드 즉시 Hydration -->
<Counter client:load />
사용 시기: 항상 보이는 중요한 컴포넌트 (헤더, 네비게이션)
2. client:idle (유휴 시 로드)
<!-- 브라우저가 유휴 상태일 때 Hydration -->
<ChatWidget client:idle />
사용 시기: 덜 중요한 위젯 (챗봇, 뉴스레터)
3. client:visible (보일 때 로드)
<!-- 뷰포트에 보일 때 Hydration -->
<LazyChart client:visible />
사용 시기: 스크롤해야 보이는 컴포넌트 (차트, 캐러셀)
4. client:media (미디어 쿼리)
<!-- 모바일에서만 Hydration -->
<MobileMenu client:media="(max-width: 768px)" />
사용 시기: 특정 화면 크기에서만 필요한 컴포넌트
5. client:only (SSR 건너뛰기)
<!-- 클라이언트에서만 렌더링 -->
<ThirdPartyWidget client:only="react" />
사용 시기: 서버에서 렌더링할 수 없는 컴포넌트
여러 프레임워크 동시 사용
React + Vue + Svelte
# 모든 프레임워크 설치
npx astro add react vue svelte
---
// src/pages/mixed.astro
import ReactCounter from '../components/ReactCounter.tsx';
import VueChart from '../components/VueChart.vue';
import SvelteCarousel from '../components/SvelteCarousel.svelte';
---
<Layout>
<h1>Multi-Framework Page</h1>
<!-- React 컴포넌트 -->
<ReactCounter client:load />
<!-- Vue 컴포넌트 -->
<VueChart client:visible />
<!-- Svelte 컴포넌트 -->
<SvelteCarousel client:idle />
</Layout>
성능 측정
Before: React SSR (Next.js)
초기 JavaScript: 85KB (gzip)
Time to Interactive: 2.5초
Lighthouse Score: 75/100
After: Astro Islands
초기 JavaScript: 8KB (gzip)
Time to Interactive: 0.5초
Lighthouse Score: 98/100
→ JavaScript 90% 감소, TTI 80% 개선
실전 프로젝트: 블로그
페이지 구조
---
// src/pages/blog/[slug].astro
import Layout from '../../layouts/Layout.astro';
import TableOfContents from '../../components/TableOfContents.tsx';
import CommentSection from '../../components/CommentSection.tsx';
import ShareButtons from '../../components/ShareButtons.tsx';
const { slug } = Astro.params;
const post = await getPost(slug);
---
<Layout title={post.title}>
<!-- 정적 콘텐츠 (JavaScript 0KB) -->
<article>
<h1>{post.title}</h1>
<time>{post.date}</time>
<div set:html={post.content} />
</article>
<!-- Island: TOC (보일 때 로드) -->
<TableOfContents
headings={post.headings}
client:visible
/>
<!-- Island: 공유 버튼 (유휴 시 로드) -->
<ShareButtons
title={post.title}
url={post.url}
client:idle
/>
<!-- Island: 댓글 (보일 때 로드) -->
<CommentSection
postId={post.id}
client:visible
/>
</Layout>
Astro vs Next.js vs Qwik
| 기능 | Astro | Next.js | Qwik |
|---|---|---|---|
| 초기 JS | 0-10KB | 85KB | 1KB |
| Hydration | 부분 (Islands) | 전체 | Resumability |
| 다중 프레임워크 | ✅ | ❌ | ❌ |
| SSG | ✅ 기본 | ✅ | ✅ |
| SSR | ✅ | ✅ | ✅ |
| 학습 곡선 | 🟢 쉬움 | 🟡 중간 | 🟡 중간 |
| 생태계 | 🌿 성장 중 | 🌳 성숙 | 🌱 새로움 |
핵심 정리
✅ Islands 아키텍처의 장점
- 압도적인 성능: 초기 JavaScript 90% 감소
- 선택적 Hydration: 필요한 부분만 인터랙티브
- 다중 프레임워크: React·Vue·Svelte 동시 사용
- SEO 최적화: 모든 콘텐츠가 정적 HTML
- Core Web Vitals: Lighthouse 점수 크게 향상
🚀 다음 단계
- Astro 공식 문서에서 심화 학습
- Astro GitHub에서 소스 탐색
- Discord에서 커뮤니티 참여
시작하기:
npm create astro@latest로 5분 만에 프로젝트를 시작하고, Islands 아키텍처로 초고속 웹사이트를 만드세요! 🚀