Astro가 무엇인지, 왜 옮기는지
이 글은 Today I Learn 시리즈의 87번째 기록입니다. (총 125개)
블로그(지금은 Jekyll)를 Astro로 옮길지 알아보며 정리한 것. 이번엔 실전 코드가 아니라 개념 위주로 담는다.
Astro란?
Astro는 콘텐츠 중심 사이트를 위한 정적 사이트 빌더다. 마크다운을 HTML로 굽는다는 점에선 Jekyll과 같은 부류인데, 세대가 다르다.
- Node(자바스크립트·타입스크립트) 기반이다. Jekyll은 Ruby다. 그래서 npm 생태계(폰트·이미지 도구 등)를 그대로 가져다 쓴다.
- 빌드 결과가 순수 정적 HTML이라, 서버 없이 Cloudflare Pages 같은 곳에 그대로 올라간다. 지금 블로그와 같은 배포 방식이다.
파일이 곧 페이지, 템플릿이 곧 코드
src/pages/에 놓은 파일이 그대로 URL이 된다(파일 기반 라우팅).about.astro를 만들면/about/이 생기는 식이다.- 화면 조각은
.astro컴포넌트로 만든다. 파일 위쪽---사이에 자바스크립트를 쓰고(빌드할 때 한 번 실행됨), 아래에 HTML을 쓴다. 공통 뼈대(헤더·푸터)는 레이아웃·컴포넌트로 재사용하고, 값은 props로 넘긴다. Jekyll의 include·레이아웃 + Liquid를 대신하는 자리다. - 핵심 차이는 템플릿이 진짜 프로그래밍 언어라는 점이다. Jekyll의 Liquid는 표현이 제한적이라 반복·계산에서 자주 막히고 우회(
{% raw %}등)가 필요한데, Astro에선if·map·fetch가 평범한 코드다. 잔디 그래프나 태그 클라우드처럼 계산이 필요한 것이 자연스러워진다.
콘텐츠를 데이터처럼 다룬다
- Content Collections — 마크다운 글들을 “스키마 있는 컬렉션”으로 관리한다. frontmatter(제목·날짜·태그 같은 머리말)를 타입으로 검증해줘서,
description을 빠뜨리면 빌드가 미리 잡아준다. - 빌드 시점에 외부 데이터를 가져와(fetch) 정적 페이지로 구울 수도 있다. 예컨대 유튜브 목록을 빌드 때 읽어와 정적 카드로 박아두는 식.
기본은 가볍게, 필요할 때만 무겁게
- Islands(부분 수화) — 기본은 자바스크립트가 0인 순수 HTML을 낸다. 그러다 인터랙티브가 필요한 위젯만 React 같은 걸로 “섬”처럼 끼워 넣는다. 수화(hydration)는 정적 HTML에 자바스크립트를 입혀 살아 움직이게 하는 것인데, 그걸 페이지 전체가 아니라 필요한 조각에만 한다는 뜻이다. 나중에 라이브 데모 위젯 같은 걸 붙이기 좋다.
- 이미지·폰트가 편하다.
astro:assets는 이미지를 빌드 때 WebP로 최적화하고(변환기 sharp가 내장), 폰트는@fontsource패키지로 자체 번들해 런타임 외부 요청을 0으로 만든다. 다만 실제 블로그 이관에선 이 둘을 안 쓰고 옛 방식 그대로 갔다 — 이미지·폰트를 원래 위치에 두고 빌드 전 복사, 폰트는 직접@font-face. 이건 Astro의 기본 기능 소개고, 실제로 뭘 썼는지는 실전 이관 TIL에 있다. - 빌드가 빠른 편이다.
Jekyll과 뭐가 다르고, 왜 옮기나
- 언어·표현력 — Jekyll(Ruby + Liquid) vs Astro(Node + 진짜 JS). Liquid 한계로 생기던 우회가 사라진다.
- 잔가시 — Ruby를 윈도우에서 쓸 때 겪는 자잘한 문제(시간대 gem 설치 등)가 없다.
- 미관 — 사이트가 예쁘고 안 예쁨은 프레임워크가 아니라 디자인(CSS)이 정한다. Astro로 옮긴다고 저절로 예뻐지는 게 아니라, 옮기는 김에 새로 디자인해야 예뻐진다. 다만 기존 테마의 기본 룩에 얽매이지 않고 빈 캔버스에서 시작할 수 있다는 게 이점이다.
- 스택 정리 — 앱은 Dart(Flutter), 업무 도구는 Python, 앞으로 C++(Unreal)까지 가는데 그 사이에서 블로그만 Ruby로 외따로 있었다. 웹을 JS로 모으면 머리에 이고 다닐 생태계가 하나 준다.
요약
- Astro는 Jekyll과 같은 “마크다운→정적 HTML” 부류지만 Node 기반이고, 템플릿이 진짜 코드라 계산이 자연스럽다.
- 파일이 곧 URL, 화면은
.astro컴포넌트, 글은 Content Collections로 스키마 검증. - 기본은 자바스크립트 0, 필요한 위젯만 섬으로(Islands). 이미지·폰트 처리가 편하다.
- 예쁨은 프레임워크가 아니라 디자인의 몫이다. 이관의 진짜 이유는 재디자인 기회 + 웹 스택을 JS로 통일하는 것.
Series: Today I Learn
1 | C++ 자료형(Data Type) 2 | MD5 vs pHash 3 | C++에서 함수의 선언과 정의 4 | Tkinter padx, pady 5 | 메모리와 포인터 변수 6 | Call by Value, Call by Reference, Call by Pointer 비교 7 | const 8 | Gemfile — Jekyll 프로젝트의 의존성 파일 9 | kramdown-parser-gfm — Jekyll의 GFM 파서 10 | 파서(Parser) 11 | AHU vs OHU 12 | I might try it vs I'll try it 뉘앙스 차이 13 | SESSION_EXPIRE_AT_BROWSER_CLOSE=True 14 | configuration key 15 | Git stash vs discard 16 | subprocess.Popen으로 Windows 탐색기에 명령어를 전달 17 | Post 잔디 분석하기 18 | Google Sheets Sync 최적화 19 | DSL (Domain Specific Language)과 GPL (General Purpose Language) 20 | 마크다운 표 그리는 방법 21 | 쿼리 파라미터(Query Parameter). 기존 QR코드 재활용 22 | Django 보안 취약점 점검 및 수정 23 | OOP Object-Oriented Programming 객체 지향 프로그래밍 24 | Fernet 대칭 암호화 25 | Jekyll 코드블록 안의 Liquid 태그 26 | insertOnConflictUpdate vs DoUpdate(target) 27 | 세션 필터 28 | 아코디언(Accordiaon) UI를 펼친상태로 만들기 29 | input의 step 30 | Word Cloud 31 | Google Sheets를 데이터 버스로(with AppSheet) 32 | Django 모델 텍스트 필드 자동 수집 패턴 33 | localStorage로 섹션 토글 상태 유지 34 | 순차 ID 생성(`select_for_update()` + `max()` 조합) 35 | 역참조 검색과 distinct() 36 | xlsx 다운로드와 로딩 오버레이 충돌 37 | Android 파일 공유 MIME 타입 38 | AssetManifest — Flutter 빌드 타임 asset 목록 런타임 조회 39 | UTF-8 BOM과 PowerShell 파일 쓰기 40 | 소리꽃 KeyBloom TIL 1 41 | 소리꽃 KeyBloom TIL 2 42 | 소리꽃 KeyBloom TIL 3 43 | 메트로놈 Simple Metronome TIL 1 44 | 소리꽃 KeyBloom TIL 4 45 | 메트로놈 Simple Metronome TIL 2 46 | 소리꽃 KeyBloom TIL 5 47 | 메트로놈 Simple Metronome TIL 3 48 | 정적 블로그 SEO 정비와 Pagefind 검색 도입 49 | 메트로놈 Simple Metronome TIL 4 50 | 안드로이드 AudioTrack 연속 재생, 실측 피커 정렬, 카메라 토치 플래시 51 | 메트로놈 Simple Metronome TIL 5 52 | 모래게임 Sandrop TIL 1 53 | 메트로놈 Simple Metronome TIL 6 54 | 모래게임 Sandrop TIL 2 55 | 모래게임 Sandrop TIL 3 56 | 메트로놈 Simple Metronome TIL 7 57 | 모래게임 Sandrop TIL 4 58 | 모래게임 Sandrop TIL 5 59 | 모래게임 Sandrop TIL 6 60 | 소리꽃 KeyBloom TIL 6 61 | 모래게임 Sandrop TIL 7 62 | 모래게임 Sandrop TIL 8 63 | 소리꽃 KeyBloom TIL 7 64 | 모래게임 Sandrop TIL 9 65 | 소리꽃 KeyBloom TIL 8 66 | 모래게임 Sandrop TIL 10 67 | 소리꽃 KeyBloom TIL 9 68 | 소리꽃 KeyBloom TIL 10 69 | 소리꽃 KeyBloom TIL 11 70 | 소리꽃 KeyBloom TIL 12 71 | 소리꽃 KeyBloom TIL 13 72 | 온실 GreenHouse TIL 1 73 | 소리꽃 KeyBloom TIL 14 74 | 온실 GreenHouse TIL 2 75 | 소리꽃 KeyBloom TIL 15 76 | 소리꽃 KeyBloom TIL 16 77 | 소리꽃 KeyBloom TIL 17 78 | 소리꽃 KeyBloom TIL 18 79 | 소리꽃 KeyBloom TIL 19 80 | 소리꽃 KeyBloom TIL 20 81 | 로그스톤 상표 셀프 출원 TIL 1 82 | 소리꽃 KeyBloom TIL 21 83 | 소리꽃 KeyBloom TIL 22 84 | 소리꽃 KeyBloom TIL 23 85 | 소리꽃 KeyBloom TIL 24 86 | MiniMacro TIL 1 87 | Astro가 무엇인지, 왜 옮기는지 읽는 중 88 | MiniMacro TIL 2 89 | 메트로놈 Simple Metronome TIL 8 90 | 메트로놈 Simple Metronome TIL 9 91 | 블로그 Astro 이관 TIL 92 | 오픈데이 Openday TIL 1 93 | 오픈데이 Openday TIL 2 94 | Unreal Engine MCP TIL 1 95 | 콘티온 Conti On TIL 11 96 | 오픈데이 Openday TIL 3 97 | 오픈데이 Openday TIL 4 98 | 오픈데이 Openday TIL 5 99 | ScorePlayer TIL 1 100 | BuildingHub TIL 1 101 | ScorePlayer TIL 2 102 | BuildingHub TIL 2 103 | ScorePlayer TIL 3 104 | Unreal Engine MCP TIL 2 105 | 궁 미로 PalaceMaze TIL 1 106 | 메트로놈 Simple Metronome TIL 10 107 | 메트로놈 Simple Metronome TIL 11 108 | 오픈데이 Openday TIL 6 109 | BuildingHub TIL 3 110 | Obsidian vault에서 코드만 빼기 — directory junction 111 | ScorePlayer TIL 4 112 | 오픈데이 Openday TIL 7 113 | URL은 바뀔 수 있는 것에 묶지 않는다 114 | 도구는 기능이 아니라 내 일에 맞는지로 고른다 115 | 돌이키기 힘든 변경은 작게 먼저 확인한다 116 | 궁 미로 PalaceMaze TIL 3 117 | 궁 미로 PalaceMaze TIL 2 118 | 소리꽃 KeyBloom TIL 29 119 | 오픈데이 Openday TIL 8 120 | BuildingHub TIL 4 121 | ScorePlayer TIL 5 122 | BuildingHub TIL 5 123 | MiniMacro TIL 3 124 | 소리꽃 KeyBloom TIL 30 125 | 궁 미로 PalaceMaze TIL 4