시작하며
프론트엔드 프레임워크의 트렌드는 정말 빠르게 바뀐다. 매년 새로운 프레임워크와 라이브러리가 등장하고, 때로는 이전의 인기 있던 도구들이 사라지기도 한다. 이러한 변화 속에서 기술 블로그 개발을 위해 적절한 기술 스택을 찾아보던 중, 성능 최적화와 콘텐츠 중심의 웹사이트 제작에 특화되어 주목 받고 있는 라이브러리를 알게 되었다.
바로 최근 큰 인기를 끌고 있는 Astro.js (일명 Astro) 웹 프레임워크이다. 이번 글에서는 Astro가 무엇인지, 그리고 어떤 이점을 가져다 줄 수 있는지에 대해 작성해보겠다.
Astro.js 를 알아보자
Astro.js 공식 홈페이지 에서 Astro를 한 문장으로 소개 하고 있다.
“The web framework for content-driven websites”
Astro란 무엇인가 ?
Astro는 블로그, 마케팅 웹사이트, 쇼핑몰 등 콘텐츠 중심의 웹사이트를 구축하기 위해 설계된 올인원 웹 프레임워크이다.
현대의 콘텐츠 중심 웹사이트에서는 성능 최적화, 유지보수 용이성, 그리고 사용자 경험 개선이 핵심 과제이다. Astro는 이러한 요구를 충족시키기 위해 성능을 최우선으로 설계되었으며, 핵심 특징인 Islands 아키텍처
와 5가지 설계 원칙
을 통해 프로젝트 진행에 적합한 선택이 되는 이유를 명확히 보여준다.
Astro의 5가지 설계 원칙
- 콘텐츠 중심: 복잡한 웹 애플리케이션을 구축하게 위해 설계된 대부분의 최신 웹 프레임워크와 대조적으로, Astro는 콘텐츠에 중점을 두는 정적 사이트 빌더 (SSG)이다.
- 서버 우선: 클라이언트 측 렌더링보다 서버 렌더링을 최대한 활용하여, 첫 번째 로드 성능이 필수적인 콘텐츠 중심 웹사이트에 이점을 제공한다.
- 기본적으로 뛰어난 성능: Javascript를 줄여, 휴대폰과 저전력 장치에서도 동일한 경험을 제공한다. Astro로 느린 웹사이트를 구축하는 것은 불가능하게 하는 것이 Astro의 목표이다.
- 사용 용이성: HTML 과 CSS만으로도 Astro 웹사이트를 개발할 수 있다. JSX 표현식과 선호하는 UI 컴포넌트 (React, Vue 등등)와 같은 복잡성은 선택사항이다.
- 개발자 중심: 수백 명의 커뮤니티 기여자가 적극적으로 유지 관리하고 14개 언어로 제공되는 문서와 같은 개발자 도구에 적극 투자한다.
Astro의 핵심 개념
Astro는 6가지 핵심 개념을 가지고 있다.
- 기본적으로 Zero JS: 사이트의 속도를 느리게 만드는 클라이언트 측 Javascript를 줄임
- Island 아키텍처: 콘텐츠 중심 웹사이트에 최적화된 컴포넌트 기반 웹 아키텍처
- UI에 구애받지 않음: React, Vue, Svelte, Solid 등을 지원
- 서버 우선: 방문자의 장치에서 값비싼 렌더링을 제거 함
- 콘텐츠 컬렉션: Markdown 콘텐츠에 대한 TypeScript 타입 안전성을 구성, 검증 및 제공
- 사용자 정의 가능: Tailwind, MDX 등 수백 가지 통합을 제공
이어 Astro의 핵심 개념들 중 몇가지를 서술해보도록 하겠다.
개념 1. 기본적으로 Zero JS
TTI는 사용자가 페이지를 완전히 사용할 할 수 있게 되는 데 걸리는 시간을 측정하는 웹 성능지표이다. 기본적으로 TTI는 자바스크립트가 무겁거나 복잡할 수록 증가하게 된다.
Astro의 Zero JS 개념은 “요청된 자바스크립트만 제공”해 브라우저에 로드 되는 자바스크립트를 최소화하여 TTI를 크게 개선하는 개념이다. Astro에서는 이를 위해 Astro 컴포넌트
를 사용하게 된다. 이는 클라이언트 측 런타임이 없는 HTML 전용 템플릿 컴포넌트로, .astro
파일 확장자를 사용한다.
Astro 컴포넌트
Astro 컴포넌트는 컴포넌트 스크립트 와 컴포넌트 템플릿 이라는 두가지 부분으로 구성된다.
컴포넌트 스크립트 는 코드 펜스 (---
)를 사용하여 컴포넌트 스크립트를 식별한다. 이는 Markdown의 프론트매터 개념과 유사하다. 컴포넌트 스크립트 영역에는 템플릿을 렌더링하는 데 필요한 Javascript 코드를 작성할 수 있다.
컴포넌트 템플릿 에는 페이지에 렌더링 될 일반 HTML과 JS 표현식을 작성할 할 수 있다.
---
// 컴포넌트 스크립트 (JavaScript)
import Header from '@ui/components/Button.astro';
import Button from '@ui/components/Button.jsx';
const fooDatas = await fetch('https://api.coldbrow.me/foo').then((res) => res.json());
---
<!-- 컴포넌트 템플릿 (HTML + JS 표현식) -->
<Header />
<ul>
{fooDatas.map((data) => <li>{data.name}</li>)}
</ul>
<Button client:load>버튼!</Button>
빌드 이후에 Astro컴포넌트의 Javascript는 모두 제거 되고 결과물은 아래와 같다.
<header>
<!-- Header 컴포넌트의 정적 내용 -->
</header>
<ul>
<li>데이터1</li>
<li>데이터2</li>
<li>데이터3</li>
</ul>
<div>
<button>버튼!</button>
</div>
여기서 중요한 점은 클라이언트에서 렌더링되지 않는다는 것이다. 기본적으로 빌드 시 HTML로 렌더링되고 컴포넌트 프런트매터에 JavaScript 코드를 포함할 수 있지만, 모든 내용은 사용자의 브라우저로 전송되기 전에 전부 제거된다. 그 결과, JavaScript가 추가되지 않아 사이트가 더 빨라진다.
개념 2. Islands 아키텍처
Islands 아키텍처는 모던 웹 개발에서 섬처럼 각각 독립적으로 작동하는 인터렉티브 UI 요소들을 페이지에 배치하는 방식의 프론트엔드 아키텍처를 의미한다. 이는 보통 정적 HTML을 먼저 렌더링하고, 필요한 부분만 클라이언트에서 동적으로 로드하는 선택적 수화를 제공하는 방식이다.
Astro는 이러한 Islands 아키텍처를 구현한 대표적인 프레임워크로, Astro에서 “Islands”란, 페이지의 대화형 UI 컴포넌트를 의미한다. 쉽게 말하자면, 먼저 사용자와의 상호작용이 필요 없는 UI를 정적 HTML로 생성한 다. 이후에 마치 섬을 띄우는 것처럼 상호작용이 필요한 UI만 Javascript를 로드하는 방식으로 동작하는 것이다.
Islands 생성
기본적으로 Astro는 UI 컴포넌트의 모든 클라이언트 측 JavaScript를 제거하고 HTML 및 CSS로 렌더링한다고 했다. 그렇다면 Island (상호작용이 필요한 UI 컴포넌트)는 어떻게 생성할까?
정적 UI 컴포넌트를 Island 바꾸려면 client:\*
클라이언트 지시어만 있으면 된다. 그러면 Astro는 클라이언트 측 JavaScript를 자동으로 빌드하고 번들링하게 된다.
<Button client:visible />
<MyReactComponent client:load />
Islands 의 이점
-
웹 사이트의 대부분은 빠르고 정적인 HTML로 제공 되며, 일부 Javascript가 필요한 개별 컴포넌트만 Hydration 과정을 통해 로드 되어 웹 사이트 성능을 크게 개선할 수 있게 된다.
-
한 페이지 내의 각 Islands는 병력적으로 로드 되어, 무겁고 느린 일부 Island가 로드 되는 것을 기다리지 않아도, 먼저 로드 되는 Islands와 상호작용 할 수 있다.
개념 3. UI Zero Lock-in
Astro는 특정 UI 프레임워크에 종속 되지 않는다. React, Vue, Preact, Svelte, Solid 와 같은 모던한 UI 프레임워크를 Astro 컴포넌트 내에 통합하여 사용할 수 있다. 이는 특정 프레임워크를 고집하지 않고, 프로젝트 요구 사항에 맞게 다양한 도구를 유연하게 조합할 수 있도록 지원한다.
---
import ReactButton from '@components/ReactButton.jsx';
import VueButton from '@components/VueButton.vue';
import { getProductDetails } from "ecommerce-package";
import ProductPageLayout from '../layouts/ProductPageLayout.astro';
const product = await getProductDetails(Astro.params.slug);
---
<ProductPageLayout>
<img src={product.imageUrl} alt={product.imageAlt} />
<h2>{product.name}</h2>
<ReactButton id={product.id} client:load />
<VueButton id={product.id} client:load />
</ProductPageLayout>
위 코드는 React와 Vue로 작성된 컴포넌트를 동시에 사용한 예제다. Astro를 사용하면 동일한 페이지에서 다양한 프레임워크의 컴포넌트를 조화롭게 활용할 수 있다. 이는, 기존의 자산을 별도의 마이그레이션 과정 없이 Astro 프로젝트에 활용할 수 있게 해준다.
마치며
Astro는 이미 콘텐츠 중심의 웹사이트 개발 도구로써 가진 수많은 장점들을 바탕으로 큰 인기를 끌며 눈에 띄는 성장을 거듭하고 있다. 국내에서는 카카오페이 기술 블로그가 Astro로 마이그레이션을 하며 성능 개선을 한 사례를 보여주기도 했다.
또한, 직접 Astro를 익혀보며 블로그를 개발해보니, 프레임워크 자체가 가볍고 기존의 UI 자산도 그대로 활용할 수 있어 러닝 커브도 굉장히 낮은 것 같다.
뿐만 아니라, 한국어 공식 문서와 정말 많은 예제와 같은 커뮤니티도 활성화 되어 있어 개발하는 내내 큰 호감이었다.
누군가 정적 사이트를 개발할 일이 있다면, 한번 쯤 다뤄보는 것도 좋은 경험이 될 것 같다.
참고