프론트엔드

프론트엔드 성능 최적화 도전기

CandDoIt 2025. 4. 14. 14:22

안녕하세요? 오늘은 개인 포트폴리오 사이트의 성능 최적화 도전기를 작성해보겠습니다.

성능의 지표는 구글 lighthouse를 기준으로 측정했습니다.

 

lighthouse 성능 측정 지표

1. 성능

웹사이트가 얼마나 빠르고 효율적으로 작동하는지를 평가합니다. 주요 측정 항목은 다음과 같습니다:

  • First Contentful Paint (FCP): 화면에 처음으로 어떤 콘텐츠가 나타나는 시간
  • Largest Contentful Paint (LCP): 주요 콘텐츠(예: 큰 이미지나 텍스트 블록)가 로딩 완료되는 시간
  • Time to Interactive (TTI): 사용자가 페이지와 완전히 상호작용할 수 있게 되는 시간
  • Speed Index: 콘텐츠가 시각적으로 얼마나 빠르게 로딩되는지를 평가
  • Total Blocking Time (TBT): 메인 스레드가 작업으로 막혀 사용자가 상호작용할 수 없는 시간
  • Cumulative Layout Shift(CLS): 페이지의 레이아웃이 로딩 과정에서 얼마나 변화하는지

개선 방법: 이미지 최적화, JavaScript 압축, 캐시 전략, 메인스레드를 차단하는 작업 분할

 

2. 접근성

웹사이트가 모든 사용자, 특히 장애가 있는 사람들에게 얼마나 잘 접근 가능한지를 평가합니다.

  • 이미지에 alt 텍스트가 있는지
  • 충분한 대비 비율 (텍스트와 배경색)
  • 키보드만으로 내비게이션이 가능한지
  • 스크린리더 사용 시 구조가 명확한지 (ARIA 속성, 올바른 heading 구조 등)

3. 권장사항

현대 웹 개발에서 보안성, 안정성, 사용자 경험 등을 높이기 위해 지켜야 할 일반적인 규칙을 평가합니다.

  • HTTPS 사용 여부
  • 비동기 스크립트 적절 사용
  • 잘못된 API 사용 금지 (예: document.write)
  • 모바일 기기에서 터치 대상 간 거리 확보 여부 등

4. 검색엔진 최적화(SEO)

검색엔진(예: Google)이 페이지를 잘 크롤링하고 인덱싱할 수 있는지 평가합니다. SEO가 좋을 수록 검색결과 상위에 노출될 수 있습니다.

  • 메타 태그 (title, meta description) 포함 여부
  • 페이지에 올바른 링크 구조가 있는지
  • 모바일 친화적인지
  • robots.txt, sitemap.xml 파일 설정 여부 등

포트 폴리오 웹서비스 개발

프론트엔드 개발자로서 경쟁력을 갖추기 위해 최근 포트폴리오 웹사이트를 제작하였습니다. 해당 사이트는 게스트 사용자가 콘텐츠를 열람할 수 있는 정보 중심의 페이지로 구성되어 있습니다. 개발에는 Next.js 14 버전을 활용하였으며, 배포는 Vercel을 통해 진행했습니다.

 

초기에는 AWS EC2 micro 인스턴스를 이용하여 직접 배포했지만, 프리 티어 기간이 만료될 때마다 계정을 새로 생성하는 것이 번거로울 것 같아 Vercel로 전환하였습니다. 개인적인 용도의 프로젝트인 만큼, 정적 자산의 캐싱 최적화와 CI/CD를 자동으로 지원하는 Vercel이 더 효율적이라고 판단했습니다. 이후 도메인 DNS 연결도 완료하여 안정적인 배포 환경을 구축하였습니다.

 

Next.js는 서버 사이드 렌더링(SSR)과 정적 사이트 생성(SSG)을 모두 지원하기 때문에 검색 엔진 최적화(SEO)에 유리하다는 장점이 있습니다. 이러한 성능상의 이유로 해당 프레임워크를 선택하였고, 스타일링에는 정적 CSS를 제공하는 Tailwind CSS를 사용하여 런타임의 CSS 계산을 최소화하였습니다.

 

또한, UI 상태 관리를 단순화 및 SSR의 적극적인 활용을 위해 React의 상태 관리 API 사용을 최소화하고, 가능한 경우 컴포넌트 간 데이터 전달을 props, URL 쿼리 파라미터, CSS 상태로 대체하였습니다. 이를 통해 복잡한 상태 관리 없이도 일관된 사용자 경험을 제공할 수 있도록 설계했습니다.

 

LCP 최적화

하지만 빌드 및 배포후 lighthouse로 성능을 측정하니 성능 측면에서 개선이 필요하다는 피드백을 볼 수 있었습니다.

이유는 바로 LCP 및 TBT에 있었고, css에서 원인을 찾았습니다. 원인은 컴포넌트에 배경화면 이미지 삽입시 style의 background-image 속성 때문이었습니다. 그래서 컴포넌트의 백그라운드 이미지를 대체할 수 있는 방법을 찾다가 "네이버 통합 검색의 웹 성능 리뷰"에서 해답을 찾았습니다.

 

메인 페이지를 보시면 사진과 텍스트가 함께 있는 UI를 볼 수 있습니다. 해당 컴포넌트를 누르면 각 섹션에 해당하는 페이지로 이동합니다. 

저는 <div> 태그 기반의 컴포넌트에 배경 이미지를 적용하고, 페이드 효과를 준 후 텍스트가 보이도록 설계했습니다.

Tailwind CSS에서는 배경 이미지를 직접 설정할 수 없어, 컴포넌트의 style prop에 { backgroundImage: 'url(example.com)' } 속성을 통해 배경을 적용했습니다.

 

그러나 background-image 속성은 브라우저가 DOM을 모두 파싱한 후 CSS 파일을 해석하면서 이미지를 요청하기 때문에, 이미지 렌더링까지 시간이 더 걸립니다. 이로 인해 LCP(Largest Contentful Paint) 성능 지표가 악화될 수 있습니다.

반면, HTML의 <img> 태그를 사용하면 브라우저가 HTML을 파싱하는 즉시 이미지 리소스를 요청합니다. 이 방식은 이미지 렌더링 속도를 단축시켜 LCP 개선에 긍정적인 영향을 줍니다.

 

특히 Next.js에서는 기본적으로 next/image 컴포넌트 사용을 권장합니다. 이 컴포넌트는 lazy loading, 이미지 최적화, placeholder 기능 등을 제공하여 성능을 더욱 향상시킵니다. 예를 들어, 화면 밖에 있는 이미지는 로딩을 지연시키고, 화면 안에 있는 이미지만 우선적으로 로드함으로써 불필요한 리소스 낭비를 줄이고 필요한 이미지만 빠르게 불러올 수 있습니다.

 

이에 따라 저는 기존의 backgroundImage 방식 대신, Next의 Image 컴포넌트를 활용하여 Card 컴포넌트의 배경을 구현했습니다.

<Card
  className="aspect-square relative p-10 mt-3 border-none text-center shadow-lg rounded-lg hover:scale-105 transition-transform duration-300 bg-cover bg-center"
>
  <Image src={AboutMe.src} alt={""} fill className="rounded-lg"/>
  <div className="absolute inset-0 bg-black bg-opacity-50 rounded-lg"></div>
  <div className="relative flex items-center justify-center space-x-2 text-white text-3xl font-semibold">
    <span>ABOUT ME</span>
  </div>
</Card>

 

그리고 다시 성능을 측정해보니 LCP와 TBT 지표가 개선되었고, 다음과 같은 결과를 얻을 수 있었습니다.

 

[참조]

https://d2.naver.com/helloworld/9582944

https://fe-developers.kakaoent.com/2022/220714-next-image/

 

Next/Image를 활용한 이미지 최적화 | 카카오엔터테인먼트 FE 기술블로그

조지영(esme) 무언갈 빠르게 좋아합니다. 그래서 변화가 빠른 FE 개발이 적성에 잘 맞습니다.

fe-developers.kakaoent.com