Astro 사이트의 모바일 PageSpeed 점수를 마침내 100점으로 만든 8가지 성능 최적화 방법
요약
Astro 프레임워크를 사용하여 모바일 PageSpeed Insights 점수 100점을 달성한 8가지 최적화 방법을 소개합니다. JavaScript 최소화, 폰트 로컬 호스팅, 프리로드 활용 등 실질적인 성능 개선 전략을 다룹니다.
핵심 포인트
- Astro의 아일랜드 아키텍처를 통한 JS 전송량 최소화
- Google Fonts 대신 로컬 .woff2 파일 호스팅 및 font-display: swap 사용
- LCP 개선을 위해 화면 상단(Above the fold) 폰트 프리로드 적용
- 불필요한 네트워크 요청을 줄이기 위한 정밀한 리소스 관리
여전히 그 잡기 힘든 PageSpeed Insights 100점을 달성하려고 노력 중이신가요?
저도 그랬습니다.
실제 클라이언트 프로젝트를 진행하며 80점 후반에서 90점 초반대에 머물러 있는 동안, 인정하고 싶지 않을 만큼 긴 시간을 허비했습니다. 이미지 압축, JavaScript (JS) 최소화, 지연 로딩 (Lazy loading), 사용하지 않는 CSS 제거 등 인터넷에서 권장하는 모든 방법을 시도해 보았지만, 점수는 거의 움직이지 않았습니다.
모바일이 진짜 문제였습니다. Lighthouse는 바로 그 지점에서 당신을 겸허하게 만드는 것 같습니다.
결국 우리는 제가 Astro로 구축한 왁싱 스튜디오 웹사이트인 waxedoc.com에서 목표를 달성했습니다.
모바일 PageSpeed:
- ✅ 성능 (Performance) 100
- ✅ 접근성 (Accessibility) 100
- ✅ 권장사항 (Best Practices) 100
- ✅ SEO 100
(브라우저 확장 프로그램이 결과에 영향을 미치지 않도록 모두 시크릿 창에서 테스트했습니다.)
흥미로운 점은 단 하나의 마법 같은 최적화 방법이 있었던 것이 아니라는 점입니다.
작은 개선 사항들이 모여 함께 작용했을 때 거대한 차이를 만들어냈습니다.
1. JavaScript를 적게 전송하는 프레임워크로 시작하기
이것은 거의 불공평하게 느껴질 수도 있지만, 사실입니다.
Astro는 기본적으로 정적 HTML을 렌더링하며, Islands Architecture (아일랜드 아키텍처)를 통해 명시적으로 상호작용이 가능하게 만든 컴포넌트만 하이드레이션 (Hydration) 합니다.
이 사이트의 대부분의 페이지에서 브라우저는 초기 로드 중에 JavaScript를 거의 다운로드하지 않습니다.
콘텐츠 중심의 웹사이트를 구축하고 있다면, 코드 한 줄을 최적화하기도 전에 이미 유리한 고지에서 시작하는 셈입니다.
2. Google Fonts에서 폰트를 불러오는 것을 중단하기
이 변경 사항은 제가 예상했던 것보다 훨씬 더 큰 영향을 미쳤습니다.
표준 Google Fonts <link>를 사용하면 브라우저는 다음과 같은 과정을 거쳐야 합니다:
fonts.googleapis.com에 연결- CSS 다운로드
fonts.gstatic.com에 다시 연결- 마침내 폰트 파일 다운로드
이는 커스텀 폰트가 로드되기 시작하기도 전에 여러 번의 네트워크 요청을 발생시킵니다.
대신, 저는 .woff2 파일을 직접 다운로드하여 로컬에 호스팅했습니다.
@font-face {
font-family: "Playfair Display";
font-weight: 600;
...
font-display: swap 또한 매우 중요합니다. 이 설정은 커스텀 폰트가 다운로드되는 동안 텍스트가 보이지 않는 상태로 유지되는 대신, 폴백 폰트 (fallback font)를 사용하여 즉시 나타나게 해줍니다.
3. 실제로 사용하는 폰트만 프리로드(Preload) 하세요
제가 배운 한 가지는 브라우저가 @font-face 규칙을 본다고 해서 즉시 폰트를 다운로드하지는 않는다는 점입니다.
브라우저는 먼저 특정 요소가 실제로 해당 폰트를 사용하는지 확인해야 합니다.
Above the fold(화면 상단 영역)에서 사용되는 폰트에 대해 프리로드 힌트 (preload hints)를 추가하는 것은 LCP를 줄이는 데 도움이 되었습니다.
<link
rel="preload"
as="font"
...
하지만 한 가지 주의할 점이 있습니다. 정말로 필요한 폰트만 프리로드하세요.
저는 CSS에 선언되어 있지만 어디에서도 사용되지 않는 두 개의 폰트 파일을 가지고 있었습니다. 이를 프리로드하는 것은 대역폭만 낭비할 뿐만 아니라, 사용되지 않는 프리로드에 대한 Lighthouse 경고를 발생시켰습니다.
4. 크리티컬 CSS (Critical CSS)를 인라인화하세요
외부 스타일시트 (External stylesheets)는 렌더링을 차단합니다.
브라우저가 이를 다운로드하고 파싱할 때까지 페이지를 그릴 (paint) 수 없습니다.
Astro는 이 과정을 놀라울 정도로 쉽게 만들어 줍니다.
// astro.config.mjs
export default defineConfig({
build: {
...
이 설정 하나만으로 첫 번째 페인트 (first paint) 전의 추가적인 네트워크 요청을 제거할 수 있습니다.
5. LCP 이미지에 실제 반응형 이미지를 제공하세요
이것은 가장 저지르기 쉬운 실수 중 하나입니다.
sizes 속성을 추가하는 것만으로는 충분하지 않습니다.
적절한 srcset이 없다면 브라우저는 여전히 선택할 수 있는 이미지가 하나뿐이며, 이는 보통 여러분의 휴대폰이 데스크톱에서 사용하는 것과 동일한 거대한 이미지를 다운로드하게 된다는 것을 의미합니다.
Astro의 <Image> 컴포넌트는 이 작업을 간단하게 만들어 줍니다.
<Image
src={image}
width={image.width}
...
가장 큰 콘텐츠 페인트 (Largest Contentful Paint, LCP) 이미지(보통 히어로 이미지)의 경우, 다음을 추가로 적용하세요:
fetchpriority="high"
이렇게 하면 브라우저가 워터폴 (waterfall) 중간에 이미지를 발견하는 대신, 해당 이미지의 다운로드를 우선시하도록 지시할 수 있습니다.
6. 적절한 캐시 헤더 (Cache headers)를 설정하세요
이 부분은 쉽게 간과될 수 있습니다.
빌드 과정에서 생성된 해시된 에셋 (Hashed assets)은 불변 (immutable)이므로, 일 년 내내 안전하게 캐싱할 수 있습니다.
Firebase Hosting에서는 다음과 같이 추가했습니다:
"headers": [
{
"source": "**/_astro/**",
...
이것은 기본적으로 비용이 들지 않는 성능 향상입니다.
7. box-shadow 또는 text-shadow 애니메이션을 사용하지 마세요
이 부분은 저를 놀라게 했습니다.
애니메이션은 완벽하게 부드러워 보였지만, Lighthouse는 이를 비합성 애니메이션 (non-composited animations)으로 표시했습니다.
그림자 (shadow)에 애니메이션을 적용하면 브라우저가 매 프레임마다 다시 그리기 (repaint)를 수행해야 합니다.
더 나은 접근 방식은 그림자는 정적으로 유지하고 opacity 또는 transform만 애니메이션화하는 것입니다.
.neon {
text-shadow: 0 0 6px currentColor;
animation: flicker 3s infinite;
...
시각적 효과는 동일합니다.
브라우저의 작업량은 줄어듭니다.
8. 강제 동기 레이아웃 (forced synchronous layouts)을 피하세요
스크롤하거나 드래그하는 동안 getBoundingClientRect()와 같은 메서드를 반복적으로 호출하고 있다면, 아마도 브라우저가 매초 수십 번씩 레이아웃을 재계산하도록 강제하고 있을 것입니다.
대신, 해당 값들을 한 번만 읽고 재사용하세요.
let box = null;
frame.addEventListener("pointerdown", () => {
...
대단한 변화처럼 들리지 않을 수도 있지만, 이러한 작은 변화들이 모여 큰 차이를 만듭니다.
실제로 100점을 달성하게 해준 것들
갑자기 Lighthouse 점수를 20점이나 올려주는 단 하나의 최적화 방법은 없었습니다.
하나의 작은 문제를 하나씩 해결해 나가는 과정이었습니다.
폰트 (Fonts)가 조금 더 빨리 로드되었습니다.
이미지 (Images)가 조금 더 작아졌습니다.
렌더링 (Rendering)이 조금 더 일찍 시작되었습니다.
자바스크립트 (JavaScript)가 메인 스레드 (main thread)를 방해하는 정도가 조금 줄어들었습니다.
이러한 개선 사항들이 충분히 쌓인 후에야 점수가 마침내 100점에 도달했습니다.
더 중요한 것은, 사이트가 실제로 더 빨라졌다는 점입니다. 단순히 Lighthouse 점수뿐만 아니라 실제 방문자들에게도 말이죠.
만약 단순화된 데모가 아닌 실제 운영 중인 웹사이트에서 이러한 최적화가 적용된 모습을 보고 싶다면:
[IMG:1]
이러한 최적화가 적용된 실제 사이트를 확인해 보세요. 모바일 PageSpeed Insights에서 지속적으로 100점을 기록하는, Astro 기반의 실제 비즈니스 웹사이트입니다.
<a href="https://waxedoc.com" class="ltag-offer__button crayons-btn crayons-btn--primary">Visit Waxed OC</a>
[IMG:2]
궁금합니다. 최근 여러분이 해결하기 가장 어려웠던 Lighthouse 감사 (audit) 항목은 무엇인가요? 폰트인가요? 이미지인가요? 서드파티 스크립트 (Third-party scripts)인가요? 아니면 완전히 다른 무엇인가요?
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기