프론트엔드 성능 최적화 톺아보기

Derhon·2023년 6월 30일
3
post-thumbnail

본문은 SKT DEVOCEAN Tech 세미나와, 개인적으로 학습하고 경험했던 프론트엔드 성능 최적화 지식을 바탕으로 작성되었습니다.
피드백 정말 완전 대 환영입니다!

최근 프론트엔드 생태계에서 성능 최적화와 관련된 이슈가 핫토픽이었다.
이었다기보단 여전히 중요하고, 앞으로도 프론트엔드 개발자에게 가장 필요한 덕목 중 하나로 이어질 것 같다.

나 역시 개인적으로 해당 주제에 대해 관심을 갖고 있었기 때문에 프론트엔드 성능 최적화 가이드 Cheat Sheet 스터디에 참여하기도 했고, 이번 Next.js 한글화 번역에서도 useReportWebVitals 번역의 컨트리뷰팅을 담당하기도 했다.

그러던 중 이번 SKT DEVOCEAN Tech 세미나 주제가 프론트엔드 성능 최적화라는 것을 알게 되었고, 당장 신청하여 들어보았다.
실제로 이전까지 들어왔던 훌륭한 세미나들보다 훨씬 많은 것을 배울 수 있었다.

두루뭉술하게 가이드라인을 잡아주는 느낌이 아니라, 정말 웹 성능을 측정하는 지표에 대한 구체적인 설명과, 이것이 필요한 이유, 실제 프로덕트(Ifland)에서 적용하여 개선한 사례까지...
그동안 성능 최적화에 대한 칼럼을 읽으면서도 직접적으로 와닿지 않는다고 느껴졌던 부분들이 명쾌하게 해결된 세미나였다.

2시간이라는 시간이 진짜 후딱 지나갔고, 헷갈리는 부분은 몇 번씩 돌려보면서 체화하려고 노력했다.
당장 나의 프로젝트에서도 적용하고 싶어지는 느낌이었다 진심 🐶🍯

이전까지의 나처럼, 채용 공고에서 성능 최적화 경험이 있으신 분 이라는 말을 보면 도대체 뭘 원하는 건지 이해하지 못했고, 여러 블로그 글이나 칼럼을 읽어도 직접적으로 느끼지 못했던 분들에게는 최고의 세미나가 될 것 같다.

하지만 2시간이라는 시간이 압박이 될 수 있고, 나 또한 다시 돌려보지 않고 글로 빠르게 보기 위해 이렇게 정리를 결심하게 되었다.

최대한 세미나 내용 + 그 동안의 성능 최적화 경험 (Cheat Sheet 스터디 + 프로젝트 경험 + Next.js 번역 등...)을 살려서 정리해보았다.
많은 분들에게 이 글이 도움이 되기를...!!

세미나 강연자 소개

이미지들이 세미나 중간 중간 캡쳐한 것들이라 화질이 좋지 않을 수 있습니다.
이미지에 대해 필요한 설명은 글로 정리해두었으니, 양해 부탁드립니다!

왜 성능 최적화를 해야하죠?

사실 PM, 디자이너, 백엔드 개발자들에게 프론트엔드 성능 최적화는 이해할 수 없는 부분으로 다가올 수 있다.
실제로 겨우 0초대의 로딩 시간을 줄여보기 위해서 리소스를 투자한다는 것에 고개를 젓는 프론트엔드 개발자도 많다.

To. FE 개발자

chatGPT 4.0도 인정한 성능 최적화 역량

하지만 프론트엔드 개발자에게 성능 최적화 역량은 중요한 역할 중 하나라는 점!
그리고 지금같이 생태계가 미친듯이 변화하고 기술이 범람하는 시대에서, 다양한 기술에 눈이 멀어 UX를 잊는 것은 본질을 잊는다는 것과 같다.

To. PM / 디자이너 / BE 개발자 etc.

단순히 프론트엔드 개발자의 역량 향상에 국한되는 토픽은 아니랍니다.

위 이미지는 사이트 로딩에 따른 이탈율이다.
애초에 풀이 그렇게 넓지도 않지만, 겨우 1-2초 차이일뿐인데 이탈율의 갭이 어마어마하다는 것을 알 수 있다.

사실 이 정도는 대부분이 알고있는 사실이다.

하지만 진짜 놀라운 건, 사용자 경험을 조사했을 때 "내가 찾는 정보가 해당 페이지에 있는가" 보다 "해당 페이지에 있는 정보가 얼마나 빨리 나타나는가" 가 사용자 경험에 더 큰 영향을 미치고 있다는 것이다.

심지어는 겨우 0.1초의 성능 개선이 Conversion Rate(제품이 실제로 판매될 확률)에 큰 영향을 미치고 있었다.

실제로 Tokopedia에서 성능 최적화 전 3.7초대의 로딩 시간과, 성능 최적화 후 1.7초 대의 로딩 시간에서 사용자를 트래킹했다.
그 결과, 로딩 시간을 포함했음에도 성능 최적화 후의 사용자가 더 오랜 시간동안 사이트에 머물러있었다는 것을 알 수 있었다 한다.

자, 이제 성능 최적화를 위해 리소스를 투자하는 것이 얼마나 중요한지 느껴지는가?

속도의 정의 (Core Web Vitals)

3년 전 Google IO에서 CWV, Core Web Vitals를 발표하였다.
격변하는 생태계에서 무려 이 지표가 뉴노멀이 된 이유는 아래에서 설명한다.

이전까지는?

물론 이전에도 웹 성능 측정을 위한 다양한 지표들이 사용되었다.

  • 페이지 전체의 크기
  • 네트워크 Request 수
  • etc ...

그럼에도 CWV가 각광받은 이유는, 개발자가 아닌 사용자 관점에서 정의된 지표라는 점이다.

해당 지표들을 Next.js의 공식문서 속 useReportWebVitals를 번역하며 공부한 적 있는데, 구체적인 의미와 역할에 대해서 명료하게 알게 되었다.

아래에서 함께 살펴보자!

1️⃣ LCP (Largest Contentful Paint)

화면이 처음 그려질 때, 가장 크게 보여지는 영역의 콘텐츠가 얼마나 빨리 로드되는가?

  • 보통 가장 크게 보여지는 영역의 콘텐츠는 이미지이다.
    • 고로, 해당 이미지가 얼마나 빨리 로드되는가?
  • 가령, 음식점에서 음식을 주문했는데 사장님께서 메인 메뉴를 얼마나 빨리 가져다 주는가에 대한 지표이다.
    • 메인 메뉴는 안주시고, 물이나 식기 및 밑 반찬만 계속 가져다주신다면...😥

2️⃣ FID (First Input Delay)

사용자가 최초 인풋을 행했을 때, 얼마나 빠르게 반응하는가?

  • 맨 처음 사이트가 로드 되었을 때 사용자의 최초 인터랙션에 대해 얼마나 빨리 반응하는가에 대한 지표이다.
    • 터치
    • 클릭
    • etc ...
  • 가령, 음식점에 들어가서 사장님을 처음 불렀을 때 얼마나 빨리 대답해주는가에 대한 지표이다.
    • 한 번에 빠르게 대답해주신다면 좋겠지만, 여러번 불러야 대답해주신다면...😩

3️⃣ CLS (Cumulative Layout Shift)

비주얼이 얼마나 긍정적인가?
얼마나 예쁘게 만들었는가에 대한 지표가 아님

  • 사용자가 콘텐츠를 열람하거나, 인터랙션을 행하는데에 있어서 부정적인 영향을 미치지 않는가에 대한 지표이다.
    • 광고가 화면의 메인 콘텐츠를 가리는 경우
    • 페이지가 로드되면서 이미지에 의해 버튼이 밀려나는 경우
      • 잘못 터치해서 화 잔뜩 났던 경우가 생각났다.
  • 가령, 고급 중식당에서 음식이 돌아가는 원판에서 내가 원하는 메뉴를 얼마나 쉽게 얻을 수 있는가에 대한 지표이다.
    • 내가 손을 뻗었는데, 다른 사람이 원판을 돌려버리면... 갈 곳 잃은 내 손 😱

인사이트

사용자 중심에서 속도를 정의했다는 점이, CWV롱런의 비결

개발자 중심의 지표에서 벗어나, 사용자 중심의 지표를 제안했다는 점이 CWV의 롱런 비결이다.

그럼에도 지난 5월 진행된 2023 Google IO에서 새로운 인사이트에 대한 발표가 있었다.

4️⃣ INP (Interaction to Next Paint)

기존의 CWV는 너무 최초에 국한된다.
INP will replace FID

LCDFID를 보면 알 수 있듯, 기존의 CWV최초에 국한되는 경향이 있었다.

특히 FID의 경우에는 이름에서부터 알 수 있듯 최초 인풋과 그 응답 시간에 대한 지표이다.

때문에 구글에서는 FID가 아닌 INP 지표의 사용을 공식적으로 예고하였다.

  • FID는 최초 인풋에 대한 응답
    • 하지만 실제로 음식점에 가보면 처음 들어갈 때에만 사장님을 부르는가?
    • 우리가 음식점에서 사장님을 자주 찾듯, 웹에서도 인풋은 지속적으로 존재한다.
  • INP는 웹에 존재하는 모든 인풋을 비교하여 평균낸 지표
    • 최초에 우리의 웹 사이트를 접근했을 때의 경험만 중요한게 아니라, 웹 사이트 전반에 걸쳐 사용자의 모든 경험을 기반으로 지표를 생성

성능 개선이 UX에만 좋은가?

정답은, 아니다!

프론트엔드 성능 개선은 흔히 알고 있는 SEO 최적화와도 밀접한 연관이 있다.
왜냐하면, CWV는 SEO 점수에도 포함되기 때문이다.

검색엔진은 세상에 존재하는 여러 페이지에 점수와 랭크를 부여하는데, 이 랭크는 검색엔진에 얼마나 노출되느냐와 직접적인 연관이 있다.

실제로 최상단에 노출되는 페이지들은 검색엔진에서 높은 점수를 받은 것이다.

결국 프론트엔드에서의 성능 개선은 SEO의 한 부분으로 자리 잡았고, 컨텐츠 내부의 디스크립션도 중요하지만 속도 역시 중요한 덕목이 되었음을 알 수 있었다.

성능 측정 방법

CWV를 기반으로 성능을 측정할 수 있는 여러 도구들이 존재한다.

그 중에서도 Lab Data 기반의 측정 도구와 Rum Data 기반의 측정 도구를 분류하여 확인해보자.

실제로 속도에 관심이 있고, 계속 개선하려는 의지가 있다면 아래의 서드파티 툴을 도입해보는 것도 좋을 것이다.

Lab Data 기반 측정 도구

Rum DataLab Data 모두를 기반으로 측정할 수 있는 도구들은 Rum Data 측정 도구 하위에 리스트업하였다.

말 그대로 실험 데이터를 기반으로 성능을 측정할 수 있는 도구를 말한다.

✅ Chrome DevTools

  • Lab Data를 기반으로 성능을 측정하는 실험실이다.
  • Performance Insight Lighthouse 탭에서 성능을 측정할 수 있다.

✅ Lighthouse

  • 오픈소스이다.
  • 임베드가 가능하다.
    • 내가 만든 서버에서 다른 사이트의 속도를 측정할 수 있다.

✅ Web Vitals Extension

  • 내가 방문하는 사이트마다 측정 값을 확인할 수 있는 익스텐션이다.
  • 실시간으로 확인이 가능하다.

Rum Data 기반 측정 도구

실시간 유저 데이터를 Rum Data라고 한다.
캐싱으로 인한 성능 혜택까지 포함된 데이터로, 실제 사용자가 느끼는 것은 Rum Data라고 할 수 있다.

대신 해당 페이지에 통계를 낼만한 유저가 방문했을 때에만 확인이 가능하다.

✅ PageSpeed Insights (PSI)

  • 서버를 에뮬레이팅하여, 실제 CWV값을 측정한다.
  • 실제 실험 데이터를 제공한다.
  • Page-Level 측정 도구이다.
    • 모든 하위 페이지에 대하여 측정이 진행된다.

✅ Chrome UX Report

  • 성능을 확인할 수 있는 대시보드가 있다
    • Visualization 면에서 좋다.
  • 크롬을 사용하는 유저들이 특정 웹 사이트를 방문했을 때, 지표를 집계하여 구글 데이터베이스에 저장한다.
  • PageSpeed Insights와 다르게 Origin-Level 측정 도구이다.
    • 최상위 페이지에 대해서만 측정을 진행한다.
    • 하위 페이지에 대해서는 측정을 진행하지 않는다.

✅ Search Console

  • Page-Level 측정 도구이다.
  • Origin 하위에 CWV가 좋은 페이지와 그렇지 못한 페이지를 분류하여 통계치를 보여준다.

✅ Web-vitals JS

  • 자바스크립트 라이브러리이다.
  • 실제로 사용자가 경험하는 측정치를 뽑아낼 수 있다.
    • 분석 툴로 REST 요청이 가능하다.

현업에선?

Lighthouse

  • 측정할 때마다 값이 달라질 수 있다.
  • 퍼포먼스가 개선되고 있는지 확인할 때 좋다.

Chrome UX Report

  • 지표가 개선되고 지속적으로 모니터링하기에 좋다.

PageSpeed Insights (PSI)

강연자님 말씀에 따르면, 가장 많이 사용하는 툴이라고 한다.

  • 신뢰할 수 있으면서, 설정할 수 있는 것이 많다.
  • 캐치 포인트에서 만든 웹 페이지 테스트 툴을 사용한다.
  • 구글 출신의 측정기는 크로미움에 국한되어있는 경우가 많다.
    • 다른 여러 OS까지 포함하지 못한다.

본론, 최적화 방법!

흔히 ROI가 나온다고 말 하는,
즉 투자 대비 성능 개선 여지가 높은 것을 위주로.

LCP(Largest Contentful Paint) 최적화

가장 크게 보여지는 콘텐츠의 로딩 속도를 의미하는 LCP를 최적화하는 방법이다.
하기에 언급되는 LCP 자원을 가장 크게 보여지는 콘텐츠라고 이해하면 된다.

LCP 자원이 빨리 발견되도록

주로 이미지가 되는 LCP 자원을 빨리 발견될 수 있도록 HTML에 추가한다.
CSS에서 이미지를 로드하는 방식은, CSS가 로드되기 전까지 모른다는 뜻이기 때문에, HTML에서 찾아질 수 있도록하는 것이다.

LCP 자원이 우선 다운로드 되도록

빠르게 발견되는 것도 중요하지만, 해당 리소스가 우선적으로 다운로드 되도록 설정하는 것도 중요하다.
LCP 자원을 먼저 다운로드 하라고 브라우저에게 명시한다.

CDN 사용

이전 포스팅에서 AWS CloudFront를 이야기할 때 언급했던 개념이다.

사용자로부터 물리적으로 가까운 서버에서 데이터를 전해주는 CDN을 사용하는 것도 LCP 최적화의 한 방법이다.

실제 상황에서 적용

  • 최초 렌더링시 이미지가 필요한 경우, HTML에 직접적으로 삽입하여 리소스가 사전에 발견되도록한다.
    • 최근에는 SSR을 통해서 클라이언트 사이드에서 그려지는 것을 최소화한다.
    • 일단 브라우저에서 HTML을 받았을 때, 요소들이 이미 작성되어 있도록 하는 테크닉을 통해 LCP를 개선할 수 있다.
  • 외부에서 불러오는 이미지의 경우 <link>preload 속성 값을 부여해서, 브라우저에게 먼저 로드해야한다는 것을 알릴 수 있다.
    • 외부 리소스를 참조해서 그리는 영역이 LCP 자원인 경우, HTML 헤더에 preload 시그널을 부여하면 좋다.
  • LCP 자원height를 부여하면 LCP 자원이 priority 되도록 설정할 수 있다.
  • 만약 LCP 자원이 아닌 이미지의 경우에는 Lazy-Loading을 적용할 수 있다.
    • 브라우저가 다운로드할 리소스 자체가 줄어든다.
    • 최적화가 가능해진다.

최 하단의 그래프의 경우에는 녹색 LCP 자원을 최대한 앞으로 땡겨와서 다운 받는다는 것을 의미한다.

여기서 만약 속도를 더 개선하고 싶다면, 그래프의 노란 부분(스크립트)를 defer하거나 async할 수 있다.
지금은 스크립트 다운로드가 끝나고 LCP 자원이 그려지고 있는데, deferasync의 경우에는 해당 스크립트가 지연로딩 되어도 괜찮은지 여부를 확인해야하기 때문에 복잡하다.

CLS(Cumulative Layout Shift) 최적화

다른 최적화보다는 쉬운편이다.

비주얼 요소의 평가 지표를 의미하는 CLS를 최적화하는 방법이다.

콘텐츠 사이즈 명시

콘텐츠 사이즈를 정확하게 명시해서 개선할 수 있다.
애초에 CLS가 평가하는 비주얼의 긍정적인 영향 중 큰 부분이 레이아웃이 밀려남에 따라 사용자의 잘못된 인터랙션을 유발하는 것이기 때문이다.

때문에 이미지가 들어올 자리를 미리 확보해 놓는다면, 이미지가 들어오기 전에는 아무것도 안보이는 문제가 발생할 수 있겠지만 의도치 않게 사용자가 잘못 인터랙션 하는 경우는 사라진다.
(아무것도 안보이는 문제를 해결하기 위해 스켈레톤UI를 도입할 수 있다.)

불필요한 애니메이션은 지양하기

  • 최초 로딩 시 뚝뚝 끊기는 현상을 해결하기 위해 애니메이션이나 트랜지션을 넣는 것은 좋다.
    • 단순히 예뻐보이기 위한 애니메이션 및 트랜지션은 지양한다.
    • 특히 레이아웃 자체를 흔드는 애니메이션은 좋지 않다.

BF 캐시 (Backforward Cache)

BF Cache란 브라우저에서 뒤로 가거나 뒤로 갔다가 다시 예전에 브라우징 했던 페이지로 돌아왔을 때,
해당 정보를 저장해놓고 다시 네트워킹을 하지 않는 최신 기술을 뜻한다.

  • 크로미움 기반 · 웹킷 기반 · 파이어폭스에서 사용이 가능한 기술이다.
    • 기본적으로 동작하게 설정되어 있음
  • 캐시를 막아놓은 경우, BF Cache가 동작하지 않을 수 있다.
    • 이런 경우에 캐싱을 허용하면, CLS 개선에 상당한 도움이 된다.

실제 상황에서 적용

콘텐츠 사이즈를 명시하라고 하지만, 반응형 UI가 기본이 된 현 시점에서... 이게 쉽지 않다.
때문에 일반적인 width height 보단, aspect-ratio 속성을 활용하는 것이 좋다고 한다.

aspect-ratio 속성을 이용하면 특정 이미지가 제대로 로드되기 전에 브라우저가 해당 이미지의 높이를 알 수 있고, 다른 영역에 미치는 영향을 미리 정해놓을 수 있기 때문에 CLS 개선에 좋다고 한다.

기본적으로 min-height 속성을 부여하는 것도 CLS 개선에 도움이 된다.

FID (First Input Delay) 최적화

세가지 지표의 최적화 중, 가장 어려운 편이다.
특히 최근에 등장한 INP와 맞닿아있기 때문에, 더 신경쓸 것이 많다.

태스크 분리

자바스크립트는 싱글 스레드 언어임을 기억해야한다.
즉, 어떤 리소스를 다운 받는 중에는 다른 작업을 할 수 없다.

스크립트를 다운받는 긴 시간 동안 렌더링되지 않는 문제를 해결하기 위해서
가장 필요한 자바스크립트를 먼저 다운받고, 메인스레드가 동작할 수 있게 양도할 수 있다.

실제 다운로드는 패러렐하게 여러개가 진행되지만,
메인 스레드가 어떤 일을 하고 있더라면 그것과 병렬로는 다른 일을 할 수 없기 때문이다.

때문에 태스크를 잘게 쪼개면, 사이사이에 브라우저가 유저에게 반응할 수 있게 되어 FID를 최적화하는데에 도움이 된다.

1️⃣ 코드 스플리팅 툴 이용하기

최근 유행하는 SPA 프레임워크에선 꽤나 많은 부분을 기본적으로 제공하고 있다.
코드 스플리팅 툴이 궁금하다면, 이 링크를 참고해보면 을 것이다.

번들링 툴로도 큰 스크립트나 큰 스타일 시트를 하나의 Chunk로 만들 수 있다.

2️⃣ 메인 스레드에게 양보하기

  • 브라우저가 중요한 태스크를 할 수 있도록 타임아웃 걸기
  • yield라는 Scheduled Task API도 등장함
    • 메인 스레드에게 자원 양보하는 방법
    • Idle 상태일 때 덜 중요한 태스크를 할 수 있도록 스레드를 번갈아 쓰는 방법

3️⃣ 커버리지 툴 활용하기

크롬 데브툴에 있는 Coverage 툴로 불필요한 자바스크립트를 확인할 수 있다.

4️⃣ 분석 툴 덜어내기

GA 같은 분석툴이 정말 많다.
해당 툴 덕분에 사용자가 어디에 방문하고 어떤 활동을 하는지 트래킹할 수 있지만, 이 트래킹이 많아질 수록 페이지가 무거워진다.

때문에 상시적으로 모니터링하는 부분이 아닌, 이제는 불필요해진 트래킹 태그는 덜어낼 수 있어야한다.

5️⃣ requestAnimationFrame()

window.requestAnimationFrame() 메서드는 브라우저에게 수행하기를 원하는 애니메이션을 알리고 다음 리페인트 바로 전에 브라우저가 애니메이션을 업데이트할 지정된 함수를 호출하도록 요청합니다.

해당 메서드를 활용하면 큰 렌더링 업데이트가 발생한다.
마찬가지로 최대한 지양해야한다.

6️⃣ DOM 사이즈를 최대한 작게

DOM 사이즈 측정값을 최대한 작게 줄여서 로드하고, 돔트리가 그려질 수 있도록 한다.
만약 DOM 사이즈가 너무 크면 최초 인터랙션에 반응할 수 없기 때문이다.

결국 페이지 내부 요소들을 조금이라도 컴팩트하게 가져가는 것이 중요한 키포인트라고 할 수 있다.

불필요한 자바스크립트를 줄여라

말은 쉽지만, 어느 것이 불필요한지 알기가 어렵다.
크롬 데브툴에서 어느 라인이 사용되지 않고 있는지 간단하게 확인할 수 있다.

큰 렌더링 업데이트를 지양하라

한 번에 빠르게 로드가 되고, 부분 부분 업데이트가 되어야 한다는 뜻이다.

가령 인피니티 스크롤을 예시로 들어보겠다.
만약 해당 스크롤의 로직이,

페이지 접근 > 뷰포트 최하단 접근 감지 > 데이터 로드 > 컨텐츠 영역 렌더링

라면, 최초에 페이지가 렌더링 될때 인피니티 스크롤이 동시에 한 번 더 로딩 될 수 있다.
이 경우에 컨텐츠가 전체적으로 다시 그려지기 때문에 큰 부분의 렌더링 업데이트가 일어난다.

현업 적용 사례 (feat. Ifland)

세미나에서는 실제 Ifland 개발자이신 신정민님께서 적용한 성능 최적화 사례를 말씀해주셨다.

위의 프로세스를 기반으로 성능을 개선하였다고 한다.

최적화의 여지가 있는 요소들

Render Blocking Resource 다수 존재

  • <script async>
    • HTML이 파싱되고 병렬적으로 스크립트가 다운로드 됨.
    • 다운로드 이후 지속적으로 HTML이 파싱 됨
    • HTML 파싱이 중지되는 부분이 있긴 함
  • <script defer>
    • HTML이 파싱되면서 중간에 스크립트가 다운로드 됨.
    • 파싱이 다 된 후에 스크립트가 실행됨.
    • HTML 파싱이 중지되는 부분이 없음

Ifland의 경우에는 현재 사용하지 않는 스크립트는 제거하고, 사용하는 스크립트의 경우에는 렌더 블라킹을 유발하는 요소들을 <script defer>로 변환했다고 한다.

이미지 용량 문제

  • 퍼포먼스 리스트를 확인해보면, jpeg png 보다는 webPAVIF의 이미지를 추천.
  • 지원이 가능한 매핑 포맷을 선택하여 이미지 용량 문제를 개선하였음.

Ifland의 경우에는 webP 포맷을 선택하여 적용하였다고 한다.

해상도에 맞지 않는 이미지를 사용

데스크탑과 모바일에서 동일한 이미지를 사용하는 상황

위와 같이 해상도에 맞지 안흔 이미지를 사용하는 경우가 존재했다.
위의 예시는 약간 극단적이지만, 큰 이미지를 작게 사용하는 경우에 최적화 여지가 존재한다.
가령 데스크탑과 모바일을 같은 이미지를 사용하는 경우, 각각 이미지를 분리하는 것을 권장한다고 한다.
(모바일용 이미지의 경우에는 확대를 위해 두배정도 큰 이미지로 설정한다.)

위의 이야기는 개념적 설명이었고, 실제 마크업 관점에서 바라보았을 때 해결 방법은 아래와 같다.

  • <picture> 태그와 <source> 태그를 사용한다.
    • 미디어 쿼리 속성을 태그 안에서 이용하여 어떤 이미지를 넣을지 설정할 수 있다.
    • 이미지 형식을 직접 지정할 수 있다.

실제로 위 솔루션을 적용하여 이미지 용량을 6-80% 가량 크게 감소시켰다고 한다.

네트워크 요청 낭비

  • 초기에 로드될 필요가 없는 이미지들
    • 핀터레스트와 같이 이미지가 많은 경우를 생각하면 쉽다!
    • loading="lazy"를 적용
  • 초기 로드시 이미지 요청 수를 크게 줄일 수 있음

메인 이미지가 늦게 로드됨

  • 위 네트워크 요청 낭비의 경우에는 빨리 로드될 필요 없는 이미지들이었음
  • 하지만 메인 이미지의 경우에는 빠르게 로드될 필요가 있음
    • 메인 이미지에 preload 속성을 적용함

모바일 해상도에서 아이콘 및 이미지가 늦게 로드됨

이미지 파일을 로드하는 형식이 아닌,
svg를 HTML의 인라인에 삽입 + preload 설정을 통해 로드 속도를 개선하였다고 한다.

svg를 인라인에 추가하면 서버 요청하는 횟수도 없어지기 때문에 네트워크 양 감소로 이어진다고 한다.

CSS, JS 용량 감소 여지 존재

코드 스플리팅 외에, 용량 자체를 감소할 수 있는 여지가 존재했다.
파일 자체를 압축하여 (gZip) 서버 네트워크 용량을 줄일 수 있었다고 한다.

화면 영역에 불필요한 움직임 존재

  • impact fraction
    • 로드 후에 움직이는 영역
  • distance fraction
    • 가장 많이 움직이는 영역

추가 개선

  • HTML과 JS 상 중복 코드를 제거하여 소스 경량화
  • 재방문자에 한하여, Request header 옵션 추가를 통해 백엔드 브라우저 캐싱을 적용

최적화 결과

실제 수치적으로 많이 개선되었다는 것을 알 수 있었다!

간단한 성능 최적화 팁

  • 스크립트에 옵션을 추가 (deferasync)
    • HTML이 파싱되어서 로드되기전에 렌더 블라킹을 방지할 수 있음
  • WebPAVIF 이미지 포맷을 적용해본다
    • 일반적인 이미지 확장자보다 로드 속도가 빠름
  • Image Lazy Loading 적용
    • 초기 렌더링이 필요하지 않은 이미지에 대해서 레이지 로딩을 적용함
  • 리소스 preload 옵션 적용
    • 초기 렌더링에 필요한 리소스는 preload 적용
  • 개발 코드는 작품을 만들 수 있지만, 부채가 될 수도 있음 (항상 경량화를 염두)
    • 빠르게 개발하는 것도 좋지만 부채가 될 수 있기 때문에 항상 경량화를 염두해두는 것도 좋음
  • CWV 개선은 지속적인 노력이 요구되는 작업임
    • 지속적으로 관리를 해야함. 한 번 하고 끝나는게 아님
  • 웹과 그를 위한 기술은 지속적으로 변화하고 발전함
    • 점점 더 쉽게 개선할 수 있는 기술들이 발전하고 등장하고 있기 때문에 이에 발맞춰 적용하는 것도 중요

결론

  • 웹 프론트엔드 개발자는 웹 성능 개선을 통해 서비스 향상에 크게 기여할 수 있다.
  • 웹 프론트엔드 성능 개선은 비즈니스 관점에서 상당히 중요하다
    • 로딩 시간이 길면 사용자는 이탈한다
  • 사용자 중심으로 사이트를 지소적으로 개선하는 문화를 만들 필요가 있다
  • 측정 가능한 지표를 정의하고 목표를 설정하고 달성하는 일은 재미있다
    • 인정받기까지하면 너무 좋다

개인적으로 사용자 중심으로 성능을 개선하는 문화를 만들 필요가 있다는 말이 와닿는다.
사실 어떤 프로젝트에서든 "성능 개선을 위해서 며칠정도..." 라는 이야기를 꺼내는 것을 상상하기 어렵다.

나조차도 성능 개선보다 당장 더 많은 프로덕트를 만들어내는 것이 중요하게 느껴질 때가 있는데, 프론트엔드 개발자가 아닌 사람의 입장에서는 더 심하게 느낄 것 같기 때문이다.

물론 상황 바이 상황으로 무엇이 중요한지 판단할 필요가 있겠지만, 처음 코드를 작성할 때부터 성능을 고려하며 작성하는 것이 가장 베스트가 아닐까하는 생각이 들었다.

역대급 길이의 포스팅이었지만, 개발자로 생활하면서 가장 깊게 고민하고 흥미롭게 생각하면서 작성한 글이 아닌가 싶다. 나 역시 이 글을 여러번 읽으면서 체화할 듯 하다.

+ 사전 질문

세미나 전에 들어온 사전 질문에 대한 답변 시간이 있었다.
그 중 도움이 될만한 이야기들을 추려서 요약해보았다.

  • 프로젝트가 무거워지는 것을 해결하는 방법
    • 디자인시스템의 모듈화 + 모노레포
  • 웹소켓 기반의 메신저 어플리케이션에서 스로틀링 적용했는데 딜레이 해결 방법
    • 로직 자체에서 해결 방법은 없다! 최적화 방향을 잘 잡아야함
    • 만약 애니메이션 문제라면 이를 잘 확인해보는 것도 좋을듯
  • LCP 외에 뷰포트 박의 영역이 느려졌다는 것을 인지하고 개선할 수 있는가
    • 이것 때문에 INP가 등장
  • 개발자도구 꿀팁
    • 크롬 개발자도구의 레코딩 기능 (Performance Insight 탭)
    • 페이지 로딩 장면부터 내가 원하는 장면까지 녹화해서 확인 가능
    • 네트워크에 Thread-holding을 해서 일부러 느리게 만든 다음, 어떤 요소들이 늦게 뜨는지 직접 확인
  • 코드 스플리팅 팁 (질문자는 라우팅 기준으로 한다 했음)
    • 기준이 따로 없긴한데 사이트에서 어느 기준으로 찢어야 최적화된 경험을 제공할 수 있는지 생각해보아야함
  • 뷰나 리액트에서 스크립트 옵션
    • 뷰나 리액트에서 렌더링을 위해 필수로 로드해야하는 모듈들은 defer 할 수 없음
    • 추가적으로 로드하는 라이브러리들은 defer 하는게 좋을 것 같음
    • 원칙은 동일함
    • 본질에 집중하기
  • 개발할 때 프레임워크가 불필요할까?
    • 프레임워크가 불필요한 것은 아님. 개발 속도가 빨라지고 속도도 좋아지기 때문에
    • 하지만 여전히 현업에서 제이쿼리가 아직도 많이 쓰임
    • 생산성 측에서는 프레임워크를 굳이 쓸 필요가 있을까?
    • 하지만 코드 스플리팅 등에서는 더 좋음
    • 어떤 서비스냐에 따라 달라질듯
      • 그럼에도 프레임워크에 갇혀서 최적화를 못하게 되는 경우가 있을 수 있음
        두부를 자르는데 장인의 칼이 필요한것은 아니니까
  • gzip 압축 방법
    • 리눅스 기반으로 압축을 진행함
    • 일반적으로 많이 쓰이니까 서칭해보면 될듯
  • 폐쇄형 웹사이트의 경우 라이트하우스를 내부서버에 구현해야하는가
    • WebPageTest에 Advanced Test를 가보면 특정 행동을 자바스크립트로 심을 수 있음
    • 가령 로그인 버튼을 클릭하고 "정해진 아이디와 패스워드를 입력하고 그다음에 속도를 측정해줘" 이런 명령이 가능함
    • 자바스크립트로 사용자의 행동을 어느정도 에뮬레이팅할 수 있음
  • UI 프로젝트를 배포하는데 이미지 파일 빌드 시간이 너무 오래걸림. 이미지 파일을 프로젝트 내부에 두지 않고 별도 이미지 서버에 저장하면 해소가 될까?
    • 이미지와 같은 스태틱 파일은 이미지 CDN 서비스를 많이 활용함
    • 그래서 빌드 배포에서는 많이 빠지는 편
    • (실제로 SKT에서도 이미지 스태틱은 모두 이미지 CDN 서버에 분리하였다고 함)
  • 스플리팅을 했는데 더 느려지는 이유
    • 불필요한 스크립트까지 스플리팅 되었기 때문임.
    • 불필요한 스크립트를 줄이는 것을 우선으로 작업하기
  • 아마존의 경우에는 초기 렌더링시에 저해상도 이미지로 렌더링하고, 렌더링이 완료되면 고해상도 이미지를 서버에서 불러오는 방식으로 구성해놓음. 사용자 경험 측면에서 불이익이 없나?
    • 이런 방식으로 구성한 사이트들이 굉장히 많음
    • 지표 분석할 때도 썸네일이 뜨면 로딩이 완료 되었다고 치기 때문에 사용자 경험 측면에서 오히려 좋다.

원본 영상

원본 영상은 이곳에서 확인할 수 있다

profile
🧑‍🚀 이사했어요 ⮕ https://99uulog.tistory.com/

0개의 댓글