솔미는 성장중

프론트엔드 웹 성능 최적화 본문

카테고리 없음

프론트엔드 웹 성능 최적화

solming 2024. 8. 14. 22:15
728x90

성능 측정 방법

lighthouse , speedtest

cf) 모바일로 돌리면 lighthouse 내부 성능이 안좋다. -> 모바일 80점 === 데스크탑 100점

 

Core web vitals
면접 질문 대비하자! (fcp, Icp, tti, cls, (inp))

측정항목들을 통칭하는 말

 

1. FCP (First Contentful Paint)

웹페이지에서 가장 먼저 보이는 페인트가 몇 초 걸리는지.

 

2. LCP (Largest Contentful Paint)

웹페이지에서 가장 큰 리소스가 불러와지는 시간

거의 이미지 최적화와 유사함.
(ex. 동영상, 이미지..)

 

3. TBT (Total Blocking Time)

= TTI(time to interaction) - FCP(first contentful paint)

= 상호작용이 가능한 시간 - FCP

 

3. CLS (Currulative Layout Shift)

레이아웃 쉬프트 측정
(width, height를 잡아줘야함)

 

4. INP -> 이거 최적화 하는 방법도 알아두기

다음 페인트와의 상호작용

 

 

최적화 방법

로딩 최적화 / 렌더링 최적화

 

로딩 최적화 = core web vital과 연관된 사항

렌더링 최적화 = cls와 연관된 사항. 애니메이션 

 

1. 로딩 최적화

이미지가 정말 많이 차지한다

 

이미지 최적화

  • 이미지 리사이징 (보통 cdn 사용) cf. next Image도 결국 내부 서버를 사용하는 것
    ㄴ 이미지를 canvas에 넣어 자르기 => blob으로 바꾼 후 URL로 변환 (=> 브라우저 딴에서 최적화 가능)
    ㄴ 가장 효과가 좋다
  • 이미지 포맷 최적화 
    jpg, png, webp, svg, gif, avif
    svg는 아이콘에서 많이 씀(벡터) - 최적화를 잘 하지 않음. - 본래 사이즈가 작고, 변환 시에 깨져보일 수 있기 때문에

    손실압축 vs 비손실 압축
    jpg : 손실 압축
    png: 비손실 압축

    jpg, png <-> webp, avif (브라우저 호환이 안되는 경우가 있다)

    요청 헤더에 accept를 보면 어떤 걸 지원하는지 볼 수 있다.
    cdn 사용시 f_auto를 넣어주면 최고로 효율 좋은걸로 바뀜. (보통 avif. 이미지 용량이 더 작은 경우가 많음)
    cdn 사용시 브라우저 호환성은 크게 고려하지 않아도 가능하다.
  • 이미지 퀄리티 최적화
    - 리소스 크기를 줄이는 것이 퀄리티 최적화
    - 이미지를 75%에 가깝게 줄이는 것은 잘 티가 안 난다. ( hero image는 티가 조금 날 수 있으니 주의하장)
    - 사진 안에 글자가 있는 경우엔 좀 더 깨져보일 수 있어 90%정도?
  • response image
    - 모바일, pc일 ㄹ때 다른 이미지 사이즈 or 포맷 적용 가능
    - picture 태그 사용 (max width 설정)
  • LQIP (low quality image placeholder)
    - fcp를 비약적으로 올리는 방법
    - 굉장히 낮은 퀄리티 (1%)를 부르고 - 백그라운드에서 본래 이미지 로드 - 로드 끝나면 원본으로 대체
    - 단점: network 페이로드 증가
    - gatsby 에서 이걸 지원함.
  • Sprite image
    - 하나의 이미지에 다양한 것을 넣어두고 위치를 조정하는 방식
    - 네트워크 payload를 줄임
    - 한계: 하나의 이미지만 독립적인 제어 불가능
    - http2의 등장으로 잘 안 쓰게 되었다. (50개를 병렬적으로 요청할 수 있어서 굳이 네트워크 payload를 줄일 필요가 없어짐)
  • lazy loading
    - 현재 내가 화면에 보이지 않는 이미지들은 안 부르고 있다가 스크롤 내릴 때 부름
    - img 태그의 loading="lazy" 속성 넣어주기 
    (cf. 윈도윙과 개념차이 비교하기)

next image를 왜 쓰면 안될까?

클라이언트 서버를 이용하기에 ec2가 터지거나 매우 느려질 수 있다. 이미지 최적화하느라고 서버사이드 렌더링이 느려질 수 있다.
그래서 사용자가 많은 서비스에선 잘 이용하지 않는다.

 

 

웹폰트 최적화

  • FOUT(flash of unstyled text), FOIT(flash of invisible text)
    : 브라우저에서 기본적으로 뭐를 지원해주는지가 다름. IE는 FOUT가 기본, 나머지는 FOIT가 기본
    : font-display 속성을 활용하자 (swap)
  • 포맷 최적화
    : woff2 가 젤 좋다.
  • font subset
    : 잘 안쓰는 글자 제거
    dynamic font subset : 쓰이는 것들만.  font-face의 unicode 속성 사용

 

 

 번들 최적화 (script 최적화) 

 

  • webpack을 통한 minify, uglify
    : next에선 자동으로 해줌. webpack을 쓴다면 거기서 관련 설정 해줘야 함.
  • code splitting
    : 사용하는 곳에서만 사용되는 script를 부르는 것
    : next에선 자동으로 해줌. webpack을 쓴다면 거기서 관련 설정 해줘야 함.
  • 경량화된 패키지 사용
    : ex) moment.js -> dayjs , react -> preact (react는 자체는 작지만 dom이 매우 크당)
    : 라이브러리 도입 전에 한번 검토해보는게 좋다. => https://bundlephobia.com/
 

Bundlephobia | Size of npm dependencies

Bundlephobia helps you find the performance impact of npm packages. Find the size of any javascript package and its effect on your frontend bundle.

bundlephobia.com

  • 트리 세이킹
    : tree shaking은 cjf에서 안되고 esm에서 된다. (차이점 : 컴파일 시점 vs 런타임 시점)
    ejs는 ~~시점에 ~~하기 때문에 실제로 쓰고있는지 아닌지를 알 수 있음.
    ex) lodash (cjf으로 제공하고 있는 라이브러리) vs lodash-es (esm으로 제공하고 있는 라이브러리)
         debounce 함수만 불러오기 위해선 lodash-es를 써야함. 전자는 다 불러옴.
  • http 압축
    : gzip, brolti
    : nginx에서 gzip으로 서빙을 하고 압축해제를 한다
    : brolti보다 gzip이 성능이 더 좋다.
    gzip vs brolti 알아보기

 

렌더링 최적화

 

 memo 

React.memo, useMemo, useCallback

 

cf. 왜 리액트는 상태가 같던 다르던 무조건 리렌더링하는걸까?
부모 업데이트 -> 자식 업데이트 되는 구조 때문에!

리액트 훅은 함수이기 때문에 부모 컴포넌트가 호출되면 자식의 함수들도 호출되는 것.

 

- memo를 쓰려면 props가 예전 상태와 같아야 한다. (다르면 무조건 다시 불러옴)

- 그렇다면 props가 다를때 최적화는 어떻게 할 수 있을까?
   -> windowing!

 

 windowing 

정말 많은 리스트를 불러올 때 유용하다

보통 라이브러리 많이 사용함. ex. react-window, react-vertualize...

 

windowing vs 무한스크롤?

무한스크롤은 네트워크를 최적화하는 방식  렌더링을 최적화 하지 않는다. dom에 다 남아있다.

windowing은 내가 보고있는 부분만 렌더링할 수 있도록 한다.

 

windowing과 무한스크롤을 같이 쓰면 좋은건가? 

 

 하드웨어 가속 

  • will-change
    : 변할 것임을 미리 알려준다.
    원리는??
  • translate3d(), scale3d()
     dom은 대부분 cpu를 이용해 렌더링하는데, translate3d() & scale3d()는 gpu를 사용한다. (z축에 0을 입력하면 translate와 동일)

 

 reflow / repaint 

  • width, height, left, top, right, bottom, ... : reflow를 일으킴 (reflow 일으키는 건 외우자)
    https://boxfoxs.tistory.com/409
    그래서 transform을 써야한다!! (no layout, no paint) 어떻게?
  • No Layout / No Paint
    : tranform, opacity, cursor, orpahns, perspective

ex) display > visibility > opacity 순서로 부하를 일으킨다. 

 

  • opacity 0.99
    : opacity는 no layout, no paint이기 때문에 이를 적극 활용하기 위한 특이한 기법

워커에서 받고 그걸 독립적으로 그리기?

 

* 캐시 *

캐시 저장의 주체가 각각 다르다

 

 web cache (중요!) 

저장주체 : web(브라우저)

헤더에 있다! Cache-Control ( 정적 파일을 캐시해준다) cf. max-age는 유효기간. 보통 1년이 최대

  -  css, js, image : max-age를 최대로 잡는다. (이래도 되는 이유는?! = hash값으로 저장되기에 이름이 항상 유니크하다. 이름 기준으로 캐시를 잡기에 이름이 바뀌면 캐시 다 소용없다. 빌드할 때마다 청크들의 이름이 바뀌기 때문에 1년으로 해놔도 다 사라짐.)
  -  html : max-age 0 or no-cache 로 잡는다. = 캐시를 안한다는 뜻 아님! = 검증을 한다. (html은 이름이 고정되어있어서 무조건 캐시되면 안된다)

Cache-Control이 없는 경우

- purist cache = 캐시를 설정하지 않았을 때 브라우저에서 임의로 설정하는 캐시 = 5분 = 5분 지나면 검증하고 캐시

왜 어떤건 cache control이 있고 어떤건 업음?

 

이름이 안바뀌는 애들은 cache를 적용하지 않는다. (Cache-Control: no-cache)

 

max-age 끝나면 실제로 바뀌었는지 아닌지를 검증을 한다. (Etag, Last-Modified 값을 기준으로 저장을 해뒀다가 이게 바뀌면 캐시가 바뀌었음을 인지) 바뀌었으면 다시 요청해서 다시 다운로드. 안 바뀌었으면 예전꺼씀.


max-age 동안에는 검증 조차도 안하고 무조건 캐시한다. (바뀌었어도 캐시되어있다)

 

요청 시에 if-Modified-Since와 if-None-Match라는 이름으로 값을 넘김 - 이게 Etag와 Last-Modified가 됨!

 

검증된 캐시에 대한 응답 = 304 not Modified

검증안하고 무조건 캐시 = 200

 

no-cache vs no-store

- no-cache === max-age =0 (캐시는 함)

- no-store : 절대 캐시하지 않겠다 (얘가 짱짱)

 

must-revalidate -> max-age = 0

pragma -> http1.1, 2 이전 버전에서는 pragma로 캐시를 했어야 합니다 *****(가산점 대답)

(pragma에 대해 알아보자..!)

stale-while-revalidate 
: swr, React query도 이 전략을 쓰고 있다! (리액트 쿼리의 캐시 전략)
: max-age보다 커야함. 그래야 의미가 있다. 작으면 무시됨
: max-age=1, stale-while-revalidate=59 -> 1초까지는 무조건 캐시, 1~60초까지는 일단 예전 컨텐츠 보여주는데, 그 때 백그라운드에서 검증 후 새로운 컨텐츠 받아놓음. -> 그 다음 요청 때 검증된 컨텐츠 뱉음 -> 60초 뒤부터는 컨텐츠를 그 때 뱉음 
: 예전께 보이다가 새로운 걸로 샤샥 바뀌는게 이 전략 때문.
: 이걸 안 쓰면 요청 했을 때 검증부터 시작

s-maxage, private, public
: cdn과 관련된 캐시옵션
: s-maxage = cdn에서 캐시하겠다
: private = cdn에 캐시를 만들지 않겠다.

: public = 디폴트 옵션. cdn에 캐시만들어도 상관없다

 

cache busting 알아보기

https://jongminlee0.github.io/2021/01/23/cachebusting/

 

 

캐시 속성 다 말해볼 수 있어야함..ㅋㅋㅋㅋ

 

 api cache 

저장주체: 서버

Redis 등을 이용함.

api 내부에서 db를 더 조회하지 않도록 캐시하는 것.

서버 쪽에서의 cache

 

 

 react-query cache 

저장된 주체는 메모리 (즉, 코드에 저장)

js 객체로 저장하고 있다. (queryClient안에 key를 기반으로 저장)

0으로 하면 새로고침할때까지만 저장

 

cache에 no-store 주는게 

 

ssr vs ssg

요청할 때를 생각

ssr은 새로고침할 때마다 서버에서 계속 컨텐츠 다시 만들어서 뱉어줌 = 동적인 동작이 됨.

ssg은 빌드할 때 만들고 그 결과물을 보여주는 것
isr은 갱신 시간을 정해줄 수 있다. 완전히 정적도 아니고 부하가 너무 심하게 걸리지도 않음. (stale while revalidate 방식을 씀)

728x90