복잡한뇌구조마냥

[FE] 프론트엔트 웹개발 성능 향상 본문

FE/기타

[FE] 프론트엔트 웹개발 성능 향상

지금해냥 2023. 12. 3. 16:56

❗️Problem

  • 어떻게 하면 웹 성능을 향상 시킬 수 있을지? (tree shaking 등)
  • 성능 지표는 무엇이 있는가
  • 측정 도구는 어떤 것이 있는가
  • 현재 LiveStudio의 성능을 측정해보면, 무엇을 제일 향상 시켜야 하는지
  • 다음 angular update시 구조 설계나 개발시 참고해야할 점

참고 서적 : 프론트엔드 성능 최적화 가이드 (저자 : 유동균)

⚠️성능 지표

1. First Contentful Paint (FCP)

  • 페이지가 로드될 때 브라우저가 DOM 콘텐츠의 첫 번째 부분을 렌더링 하는 데 걸리는 시간에 관한 지표
  • 총점 계산의 10% 가중치

2. Speed Index (SI)

  • 페이지 로드 중에 콘텐츠가 시각적으로 표시되는 속도를 나타내는 지표
  • 총점 계산의 10% 가중치

3. Largest Contentful Paint (LCP)

  • 페이지가 로드될 때 화면 내에 있는 가장 큰 이미지나 텍스트 요소가 렌더링되기까지 걸리는 시간을 타나내는 지표
  • 총점 계산의 25% 가중치

4. Time to Interactive (TTI)

  • 사용자가 페이지와 상호 작용이 가능한 시점까지 걸리는 시간을 측정한 지표 (클릭, 키보드 입력 등)
  • 총점 계산의 10% 가중치

5. Total Blocking Time (TBT)

  • 페이지가 클릭, 키보드 입력 등의 사용자 입력에 응답하지 않도록 차단된 시간을 총합한 지표
  • 측정은 FCP와 TTI 사이의 시간 동안 일어나며, 메인 스레드를 독점하여 다른 동작을 방해하는 작업에 걸린 시간을 총합
  • 총점 계산의 30% 가중치

6. Cumulative Layout Shift (CLS)

  • 페이지 로드 과정에서 발생하는 예기치 못한 레이아웃 이동을 측정한 지표
  • 레이아웃 이동은 화면상 요소의 위치나 크기가 순간적으로 변하는 것
  • 총점 계산의 15% 가중

⭐️ Lighthouse 10 출시

  • TTI가 항목에서 제거되고, CLS가 25%를 차지하도록 변경
  • TTI는 특정 시점을 표시하지만 네트워크 요청과 긴 작업에 지나치게 민감함
  • 불필요한 레이아웃 변경을 수행하는 사이트에 대한 초점이 높아짐.

⚠️프론트엔드 성능 측정 도구

⭐️크롬 개발자 도구

1. Network 패널

  • 현재 웹 페이지에서 발생하는 모든 네트워크 트래픽을 확인
  • 리소스 시점 및 크기를 확인

2. Performance 패널

  • 웹 페이지가 로드 될 때, 실행되는 모든 작업을 확인
  • 메인 스레드에서 실행되는 자바스크립트를 차트형태로 확인
  • 어떤 자바스크립트 코드가 느린지 확인

3. Lighthouse 패널

  • 구글에서 만든 툴, 웹 사이트 성능 측정 및 개선 방향 제시
  • 성능 점수를 측정하고 개선 가이드를 확인하여 중점 사항 분석 및 최적화

4. Coverage 패널

  • 웹 페이지를 렌더링 하는 과정에서 실행되는 코드를 보여줌
  • 각 파일의 코드가 얼마나 실행됐는지 비율로 나타냄
  • 특정 파일에서 극히 일부의 코드만 실행되어 퍼센티지가 낮다면 불필요한 코드가 많음.

⭐️PageSpeed Insights

참고 자료: https://pagespeed.web.dev/?hl=ko

  • google developers에서 제공
  • 데스크톱과 모바일 브라우저에서 웹페이지가 어떻게 작동하는지에 대한 세부 정보를 제공하는 페이지
  • 속도 보고서를 생성
 

⭐️webpack-bundle-analyzer

참고 자료: https://house261.github.io/angular/hdragon-analyzer/
참고 자료: https://www.digitalocean.com/community/tutorials/angular-angular-webpack-bundle-analyzer

  • 번들링한 파일들을 시각적으로 확인
  • 중복된 라이브러리를 각 모듈이 포함하고 있으면 웹팩 성능 저하 초래
  • webpack을 실행하거나 npm명령을 입력하면 현재 프로젝트의 번들링 파일이 어떠한 모듈을 포함하고 있고, 크기는 얼마인지 번들링 파일별로 확인

 

 

⭐️Squoosh

공식 문서: https://squoosh.app/

  • 웹에서 서비스되는 이미지 압축 도구
  • 구글에서 만듬
  • 웹에서 간편하게 이미지의 포맷이나 사이즈를 변경할 수 있음

⭐️PurgeCSS

공식 문서: https://purgecss.com/

  • PurgeCSS는 사용하지 않는 CSS를 제거해 주는 툴
  • npm에 등록되어 있음
  • 직접 CLI를 통해 실행할 수도 있음
  • webpack과 같은 번들러에서 플러그인으로 추가하여 사용할 수도 있음

⚠️성능 향상 방법

⭐️이미지 사이즈 최적화

공식 문서: https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types
참고 자료: https://velog.io/@seunghwan7305/%EC%9B%B9-%EC%84%B1%EB%8A%A5-%EC%B5%9C%EC%A0%81%ED%99%94-%EC%8A%A4%ED%84%B0%EB%94%94-1%ED%9A%8C%EC%B0%A8
참고 자료 : https://www.kimcoder.io/blog/image-optimize

1. 필요한 공간에 비해 큰 사이즈의 이미지를 사용하고 있는지 확인

2. 레티나 디스플레이는 같은 공간에 더 많은 픽셀을 그릴 수 있기 때문에
너비 기준 2배 정도 크기가 적절

  • ex ) 120px X 120px 공간 → 240px X 240px 이미지

3. API를 통해 받아오는 이미지의 사이즈 조절 방법

  • Cloudinary나 Imgix 같은 CDN을 활용하여 사용

 
  • API를 통해 전달된 image 값에 쿼리스트링을 붙여 이미지를 가공하여 전달받을 수 있도록 수정

❓이미지는 무엇이 있는가

 
약어파일 형식MIME 유형파일 확장자요약
APNG Animated Portable Network Graphics image/apng .apng
  • 무손실 애니메이션 시퀀스에 적합
    (GIF는 성능이 낮습니다)
  • AVIF 및 WebP는 성능이 더 뛰어나지만 브라우저 지원 범위는 적습니다.
  • 지원 : Chrome, Edge, Firefox, Opera, Safari.
AVIF AV1 Image File Format image/avif .avif
  • 고성능 및 로열티 프리 이미지 형식으로 인해 이미지와 애니메이션 이미지 모두에 적합한 선택
  • PNG 또는 JPEG보다 훨씬 더 나은 압축을 제공
  • AVIF를 사용할 때 더 나은 브라우저 지원(예: 요소 사용)이 있는 형식에 대한 대체를 포함해야 합니다.
  • 지원: Chrome, Firefox(정지 이미지만 해당), Opera, Safari.
GIF Graphics Interchange Format image/gif .gif
  • 간단한 이미지와 애니메이션에 적합한 선택
  • 무손실 인덱스 스틸 이미지 에는 PNG를 선호 하고 애니메이션 시퀀스에는 WebP, AVIF 또는 APNG를 고려
  • 지원 : Chrome, Edge, Firefox, IE, Opera, Safari.
JPEG Joint Photographic Expert Group image image/jpeg .jpg, .jpeg, .jfif, .pjpeg, .pjp
  • 정지 이미지의 손실 압축에 적합한 선택
  • 이미지를 더욱 정밀하게 재생해야 하는 경우 PNG를 선호
  • 더 나은 재생과 높은 압축률이 모두 필요한 경우 WebP/AVIF를 선호
  • 지원: Chrome, Edge, Firefox, IE, Opera, Safari.
PNG Portable Network Graphics image/png .png
  • 소스 이미지를 보다 정확하게 재생하거나 투명성이 필요한 경우에는 JPEG보다 PNG가 선호
  • WebP/AVIF는 훨씬 더 나은 압축 및 재생 기능을 제공
  • 지원: Chrome, Edge, Firefox, IE, Opera, Safari.
SVG Scalable Vector Graphics image/svg+xml .svg
  • 벡터 이미지 형식; 다양한 크기로 정확하게 그려야 하는 사용자 인터페이스 요소, 아이콘, 다이어그램 등에 이상적
  • 지원: Chrome, Edge, Firefox, IE, Opera, Safari..
WebP Web Picture format image/webp .webp
  • 이미지와 애니메이션 이미지 모두에 탁월한 선택
  • WebP는 더 높은 색상 깊이, 애니메이션 프레임, 투명도 등을 지원하여 PNG 또는 JPEG보다 훨씬 더 나은 압축을 제공
  • AVIF는 약간 더 나은 압축을 제공하지만 브라우저에서 잘 지원되지 않으며 프로그레시브 렌더링을 지원하지 않음
  • 지원: Chrome, Edge, Firefox, Opera, Safari
 

❌ 웹에서 사용을 피해야 하는 이미지 형식

❓이미지는 어떻게 사용해야 하는가

 
유형설명최적화
svg
  • 로고, 텍스트, 아이콘과 같은 기하학적인 모양으로 구성된 이미지
  • 해상도 및 배율에 독립적이므로 다양한 크기로 표현해야하는 경우에도 좋다.
  • 이미지가 복잡하여 svg 마크업 양이 많아지는 경우에는 사용하면 좋지 않다.
  • svg를 서빙해 주는 서버에서 svg에 대한 gzip 설정.
  • xml내 불필요한 요소들 제거 / xml node 구조 변경
  • 플러그인 아키텍처로 이루어진 SVGO(SVG Optimizer)의 플러그인 리스트들을 확인하면 어떤 항목들을 최적화시킬 수 있는지 알 수 있다.
gif
  • 간단한 도형, 로고, 만화 그림처럼 색이 별로 필요 없는 이미지와 애니메이션을 표현하고자 할 때
  • 무손실 압축을 하기 때문에 프레임이 많아지면 용량도 매우 비대
  • 던 브라우저만 지원해도 된다면, APNG, AVIF를 사용하는게 훨씬 좋을 수 있다.
  • 해상도 줄이기
  • 사용 색상 줄이기
  • 애니메이션 프레임 줄이기
이미지의 표현이 의도한 대로 사용자에게 전달 할 수 있는 방법이 아님.
jpeg
  • 사진과 같이 복잡한 패턴과 색상을 갖는 이미지
  • 웹 페이지 전체를 뒤덮는 배경 이미지
  • PC 웹의 배경 이미지는 대부분 고해상도로 되어 있는데 어느정도 이미지 손실을 감안하더라도 성능을 위해 jpeg를 사용하는 것이 좋다.
  • 문자, 선, 격자 등 단색이나 뚜렷한 윤곽선을 가지는 이미지에서는 품질 저하
    → PNG 같은 다른 형식을 사
  • 불필요한 메타데이터 제거
  • EXchangable Image File, Adobe's Extensible Metadata Platform 등
  • jpeg 퀄리티를 (적당히)낮은 값으로 설정.
  • 퀄리티가 낮아지면 손실율이 올라가기 때문에 절충점을 찾아 여러 품질로 시도
png
  • 문자, 선, 격자 등 단색이나 뚜렷한 윤곽선을 가지는 이미지
  • 알파 채널을 표현해야되는 이미지
  • 무손실 압축을 하기 때문에 웹상에서 이미지가 추가적으로 편집/저장될 가능성이 있을 경우에 사용해도 좋다.
  • 애니메이션을 표현해야 한다면 확장 포맷인 APNG 형식을 사용
  • 이미지에 사용되어지는 색상이 많을 경우, png의 용량이 비대해질 수 있으므로 다른 형식 사
  • 불필요한 메타데이터 제거.
  • 각 픽셀을 표현하는 color depth(색 심도)를 8-bit indexed color로 설정.

파일 압축 사이트 모음

JPG / PNG 압축 사이트

iloveimg 또는 tinypng 

JPG / PNG To Webp 변환 사이트

cloudconvert 또는 convertio 등

Webp 압축 사이트

11zon

압축 및 변환에 가장 좋은 프로그램

photoscape X를 사용하시는 것이 가장 좋다. (압축 제한 없음, 일괄 압축 가능)

📌 핵심

  • 이미지를 사용하지 않아도 되는 상황이라면 이미지를 사용하지 않는게 좋다.
  • 표현하는 컨텐츠에 따라 적합한 포멧을 사용하는 것이 좋다.
  • 각 이미지 타입에 맞는 최적화를 적용하는 것이 좋다.
  • 웹 페이지에서 보여주는 이미지의 해상도와 최대한 동일한 해상도를 가진 레스터 이미지 제공
  • srcSet, sizes 속성 등을 통하여 반응형의 필요한 크기의 이미지를 제공

⭐️병목 코드 최적화

📚 병목 코드란 ?

서비스를 느리게 만드는 코드를 병목 라고 한다.

※ 이런 병목 코드를 어떻게 찾아내고, 어떤 방법으로 최적화할수있을까?

⇒ 구글 개발자 도구에 퍼포먼스 탭에 들어가 용량 시간 순으로 나열

1. Performance 패널 살펴보기

  • Perfomance 패널에서 새로고침 버튼을 누르면 페이지 로드간 작업 기록
  • 네트워크 설정을 Fast 3G로 변경하면 서비스 상태를 더 상세히 볼 수 있음.
 

① CPU 차트, Network 차트, 스크린샷

  • CPU 차트는 시간에 따라 CPU가 어떤 작업 리소스를 사용하고 있는지 비율 표시
    • 노란색 - 자바스크립트
    • 보라색 - 렌더링/ 레이아웃
    • 초록색 - 페인팅
    • 회색 - 기타 시스템 작업
    • 어느 타이밍에 어떤 작업이 주로 진행되고 있는지 파악
    • 빨간색 선은 병목이 발생하는 지점을 의미 - 특정 작업이 메인스레드를 오래 사용
  • Network 차트
    • CPU 차트 밑 막대 표시
    • 위쪽의 진한 막대는 우선순위가 높은 네트워크 리소스, 아래는 우선순위 낮은 리소스
  • 스크린샷 리스트
    • 서비스가 로드되는 과정

② Network 타임라인

  • Network 패널과 유사하게 서비스 로드 과정에서의 요청을 시간 순서에 따라 보여줌
    • 왼쪽 회색 선 : 초기 연결 시간
    • 막대의 옅은 색 영역: 요청을 보낸 시점부터 응답을 기다리는 시점까지의 시간 (TTFB, Time to First Byte)
    • 막대의 짙은 색 영역: 콘텐츠 다운로드 시간
    • 오른쪽 회색 선: 해당 요청에 대한 메인 스레드 작업 시간

③ Frames, Timings, Main

  • Frame 섹션
    • 화면의 변화가 있을 때마다 스크린샷을 찍어 보여줌
  • Timings 섹션
    • User Timing API를 통해 기록된 정보를 기록합니다.
  • Main 섹션
    • 브라우저의 메인 스레드에서 실횡되는 작업을 플레임 차트로 보여줌
    • 어떤 작업이 오래걸리는지 파악 용도
  • 그 외 Raster, GPU 등 작업 확인 가능

④ 하단 탭

  • Summary
    • 선택 영역에서 발생한 작업 시간의 총합과 각 작업이 차지하는 비중을 보여줌
  • Bottom-Up
    • 가장 최하위에 있는 작업부터 상위 작업까지 역순으로 보여줌
  • Call Tree
    • Bottom-Up과 반대로 가장 상위 작업부터 하위 작업 순으로 작업 내용을 트리뷰로 보여줌
  • Event Log
    • 발생한 Event를 보여줌
    • Loading, Experience Scripting, Rendering, Painting

2. 병목 코드 개선

  • 특수 문자 효율적으로 제거하기
    • ex) 문자열 제거 용도의 substring, concat 함수 → replace 함수로 전환
  • 작업량 줄이기
    • 전체 반복문을 부분 반복문으로 변경
    • Promise 나열을 Promise.all을 이용하여 병렬 처리
    • await으로 오래걸리는 함수를 기다리는 것보다 먼저 끝낼 수 있는 작업은 빨리 끝나도록 조

⭐️코드 분할

1. 번들 파일 분석

2. 코드 분할이란?

  • 말 그대로 코드를 분할 하는 기법으로 하나의 번들 파일을 여러 개의 파일로 쪼개는 방법
  • 분할된 코드는 사용자가 서비스를 이용하는 중 해당 코드가 필요해지는 시점에 로드되어 실행 - 지연로딩
  • 페이지별로 코드를 분할 하는 방식
  • 모듈별로 코드를 분할하는 방식

📌 핵심

  • 불필요한 코드 또는 중복되는 코드 없이 적절한 사이즈의 코드가 적절한 타이밍에 로드 되도록 하는 것

3. 코드 분할 적용

  • 코드 분할을 하는 가장 좋은 방법은 동적 import를 사용하는 방법
import { add } from './math'

console.log('1 + 4 =', add(1, 4));

해당 모듈은 빌드 시 함께 번들링 됩니다.

  • 동적 (dynamic) import
import('add').then((module) => {
  const { add } = module
  
  console.log('1 + 4 =', add(1, 4));
})

위와 같이 import를 사용하면 빌드할 때가 아닌 런타임에 해당 모듈을 로드합니다.

동적 import 구문은 Promise 형태로 모듈을 반환하기 때문에 promise 밖으로 빼내야함.

  • angular에서 사용하는 예시
const DataServiceImport = () => 
  import('./data.service').then((m) => m.DataService);

@Component({
  template: `
    <ul>
      <li *ngFor="let todo of todos$ | async">
        {{ todo.title }}
      </li>
    </ul>
  `,
  standalone: true,
  imports: [NgFor, AsyncPipe],
})
export class AppComponent {
  private dataService$ = lazyService(DataServiceImport);

  todos$ = this.dataService$.pipe(concatMap((s) => s.getTodos()));
}
  • webpack은 동적 import 구문을 만나면 코드를 분할하여 번들링 합니다.

LiveStudio의 일부 번들을 가져왔습니다.

적용하면 component에서 사용하는 component만 사용하도록 변경될 것입니다.

⭐️텍스트 압축

1. production 환경과 development 환경

  • 서비스 측정 시에는 production 환경으로 빌드된 서비스의 성능을 측정해야함

2. 텍스트 압축이란

  • 웹 페이지를 로드할 대는 다양한 리소스를 다운로드
    • ex ) HTML, CSS, 자바스크립트와 같은 텍스트 형태의 파일
  • 텍스트 압축이란 말 그대로 텍스트를 압축하는 것
  • HTML, CSS, 자바스크립트는 텍스트 기반 파일이기 때문에 압축 기법 적용 가능
  • 압축 여부 확인 하는 방법은 HTTP 헤더를 확인하면 됨

3. 텍스트 압축 적용

참고 자료: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding
참고 자료: https://stackoverflow.com/questions/44758755/how-to-enable-gzip-compression-in-angular-cli-for-production-build

현재 Livestudio는 content-encoding 값이 전달 되지 않는 것으로 확인됨.

라이브러리를 통해 gzip 형식으로 보낼 수 있는 것 같으나 확인 필요.

⭐️애니메이션 최적화

1. 브라우저 렌더링 과정

 

 
  • DOM + CSSOM
    • HTML과 CSS 등 화면을 그리는데 필요한 리소르를 파싱하는 단계에서 만들어지는 형태
  • 렌더 트리
    • DOM과 CSSOM의 결합으로 생성
    • 화면에 표시되는 각 요소의 레이아웃을 계산
  • 레이아웃
    • 화면 구성 요소의 위치나 크기를 계산하고 배치
  • 페인트
    • 화면에 배치된 요소에 색을 채워넣는 작업 ( 배경 색, 글자 색, 테두리 색 등)
    • 효율적인 페인트 과정을 위해 구성 요소를 여러 개의 레이어로 나눠 작업하기도 함.
  • 컴포지트
    • 여러 개의 레이어로 쪼개서 그려진 화면을 하나로 합성하는 단계

2. 리플로우와 리페인트

  • 리플로우
    • 기존 화면에서 화면이 변경되었을 때 새로 생성된 화면을 구성에 맞게 재렌더링하는 과정
    • 주요 렌더링 경로의 모든 단계를 재실행하기 때문에 브라우저 리소스를 많이 사용
    • ex ) 자바스크립트에 의해 화면 요소 크기 변경 → 사이즈를 계산하여 화면을 새로 그림
  • 리페인트
    • 레이아웃 단계를 건너뛴 후 색을 입히는 페인트 단계와 레이어를 합성하는 과정
    • 레이아웃 단계를 건너 뛰기 때문에 리플로우 작업도나는 빠름
    • ex) 자바스크립트에 의해 글자 색 변경 → 레이아웃 유지 → 색상 할당 및 컴포지트

3. 애니메이션 최적화

  • GPU를 활용하여 레이아웃 단계와 페인트 단계를 건너 뛸 수 있는 속성을 사용
    • ex) transform, opacity
  • 색상이 변경되도록 되어 있는 부분을 opacity로 구성하여 브라우저 리소스 단축
  • 막대의 너비를 100%로 채워두고 필요에 따라 transform의 scale을 이용하여 비율을 조정 등

⭐️컴포넌트 사전 로딩

1. 지연 로딩의 단점

  • 최초 페이지를 로드할 때 당장 필요 없는 모달과 관련된 코드가 번들 되지않아 초기 로딩 속도나 자바스크립트의 실행 타이밍이 빨라져서 화면이 더 빨리 표시된다는 장점이 있음.
  • 초기 화면 로딩에는 효과적이나, 모달을 뜨기까지 약간의 지연 발생

2. 사전 로딩을 고려할 수 있는 타이밍

  • 사용자가 버튼 위에 마우스를 올려놨을 때 (mouseenter)
    • 마우스가 버튼에 올라갔는지 확인한다.
    • 마우스가 올라온 시점에 Modal 데이터를 로드한다.
    • 마우스 커서를 버튼 위에 올리고 클릭까지 300~600ms 시간차 동안 새로운 파일 로드에 충분
  • 최초에 페이지가 로드되고, 모든 컴포넌트의 마운트가 끝났을 때
    • 모달 컴포넌트 크기가 커서 로드에 1초 이상이 필요할 때 사용
    • 모든 컴포넌트의 마운트가 완료된 후, 브라우저에 여유가 생겼을 때 모달을 추가로 로드

📌 핵심

  • 사전 로드 방법이 2가지만 있는게 아님.
  • 서비스나 기능의 특성에 따라 방법 적용
  • 중요한 것은 어느 타이밍에 사전 로드하는 것이 해당 서비스에서 가장 합리적인지 판단하는 일

⭐️이미지 사전 로딩

  • 이미지가 제때 뜨지 않아 생기는 현상

1. 이미지 사전 로딩

  • 이미지는 화면에 그려지는 시점, HTML 또는 CSS에서 사용하는 시점에 로드됨
  • 자바스크립트의 Image 객체를 사용하여 직접 로드하는 방법이 있음
const img = new Image();
img.src = '{이미지 주소}'
  • 테스트 진행시 Disable cache 옵션 체크 해제
    • 이미지 사전 로딩이 가능한 이유는 이미지를 로드할 때 브라우저가 해당 이미지를 캐싱
    • 체크되어 있으면 이미지 리소스에 대해 캐시하지 않아 매번 새로 불러옴
    • 체크를 풀면 다른 리소스도 캐시를 사용하기 때문에 정확한 분석이 어려워 질 수 있음.
    • 새로고침할 때 캐시 비우기 및 강력 새로고침을 이용해야함

⭐️폰트 최적화

1. FOUT, FOIT

폰트 다운로드가 완료되지 않아 정상적인 폰트가 나오지 않고 다운로드 완료 후 변경되는 현상

  • FOUT
    • Edge 브라우저에서 폰트를 로드하는 방식
    • 폰트의 다운로드 여부와 상관없이 먼저 텍스트를 보여준 후 폰트 다운로드 완료 후 폰트를 적용
  • FOIT
    • 크롬, 사파리, 파이어폭스 등에서 폰트를 로드하는 방식
    • 폰트가 완전히 다운로드되기 전까지 텍스트 자체를 보여주지 않다가 다운되면 폰트를 적용
    • 크롬의 경우 완전 FOIT가 아닌 3초만 기다리는 FOIT (3초 이후에는 기본 폰트)

2. 폰트 최적화 방법

  • 폰트 적용 시점 제어하기
    • 제목 등 중요한 텍스트는 FOIT를 쓸 경우 사용자에게 빠르게 전달이 어려움
    • 사용자에게 꼭 전달하지 않아도 되는 텍스트는 FOUT를 쓸 경우 폰트 변경 시 시선이 분산됨
    • fontfaceobserver 라이브러리를 이용해서 font가 다운로드 완료되는 시점을 알 수 있음
      • ex) 폰트 로드 상태에 따라 opacity를 0 → 1, transition을 이용하면 서비스 체감이 좋아짐
 
// CSS의 font-display 속성을 사용하면 폰트가 적용되는 시점을 제어할 수 있음
@font-face {
  font-family: BMYEONSUNG;
  src: url('./asset/fonts/BMYEONSUNG.ttf')
  font-display: fallback;
}
  • 폰트 파일 크기 줄이기
    • 폰트 포맷 변경
      • TTF, OTF의 압축하여 웹에서 더욱 빠르게 로드 할 수 있도록 하는 포맷이 WOFF
      • WOFF와 WOFF2는 브라우저 호환성 문제가 있을 수 있음
      • 따라서 낮은 용량 포맷부터 순서대로 적용
      • https://transfonter.org/ 를 통해 WOFF와 WOFF2로 변환할 수 있음
// Data-URL을 이용하여 폰트 적용
@font-face {
  font-family: BMYEONSUNG;
  src: url('./asset/fonts/BMYEONSUNG.woff2').format('woff2'),
    url('./asset/fonts/BMYEONSUNG.woff').format('woff'),
    url('./asset/fonts/BMYEONSUNG.ttf').format('truetype'),
    url('./asset/fonts/BMYEONSUNG.otf').format('opentype');
  font-display: block;
}

⭐️캐시 최적화

📚 캐시란?

캐시는 자주 사용하는 데이터나 값을 미리 복사해둔 임시 저장 공간 또는 저장하는 동작

  • 캐시의 종류
    • 메모리 캐시 : 메모리에 저장하는 방식 - RAM
    • 디스크 캐시 : 파일 형태로 디스크에 저장하는 방식

※ 어떤 캐시를 사용할지는 직접 제어할 수 없음

※ 브라우저가 사용 빈도나 파일 크기에 따라 특정 알고리즘에 따라 처리

1. Cache-Control

  • 5가지 값이 조합되어 들어감
  • public과 private로 설정하면 max-age에서 설정한 시간만큼 서버에 사용 가능 여부를 묻지않고 사용
  • 유효기간이 지났다면 서버에 캐시된 리소스 사용 여부를 확인하고 유효 시간 만큼 연장
  • 웹 서버와 브라우저 사이를 연결하는 중간 캐시 서버를 적용하고 싶지 않다면 private 사용
  • max-age는 초단위 설정
//max-age=0은 no-cache와 동일
Cache-Control: public, max-age=0

2. 캐시 적용

  • 캐시의 응답 헤더는 서버에서 설정

3. 적절한 캐시 유효 시간

  • HTML: 일반적으로 no-cache 적용
    • 항상 최신 버전의 웹서비스 제공 이유
    • 캐시된 HTML에서 이전 버전의 자바스크립트나 CSS를 로드하게 되므로 캐시 시간 동안 최신 버전의 웹서비스를 제공하지 못함
  • JS/CSS : 파일명에 해시를 함께 가지고 있음 (ex - main.bb8aa28.chunk.js)
    • 코드가 변경되면 해시도 변경되어 완전히 다른 파일이 되어버림
    • 31536000 = 1

⭐️불필요한 CSS 제거

1. Coverage 패널

  • 자바스크립트는 동작에 따라 사용 비율이 변경되므로 어느정도 감안해야함
  • CSS 리소스는 if를 통한 분기가 거의 없기 때문에 사용하지 않는다는 표시가 거의 실제와 같음
  • 파란 막대 - 해당 코드가 실행되어 적용 되었음
  • 빨간 막대 - 해당 코드가 실행되지 않았음

2. PurgeCSS

  • PurgeCSS는 파일에 들어 있는 모든 키워드를 추출하여 해당 키워드를 이름으로 갖는 CSS 클래스만 보존
  • 나머지 매칭되지 않은 클래스는 모두 지우는 방식으로 CSS 파일을 최적
  • 사용 이후 스타일이 깨지는 모습이 나온다면, 텍스트 키워드 추출할 때 인식을 못해서 잘리는 현상이 생김
  • 옵션을 통해 이름 매칭을 정상적으로 필터링 하도록 수정하면 됨

⭐️메모이제이션으로 코드 최적화

📚 메모이제이션이란?

한 번 실행된 함수에 대해 해당 반환 값을 기억해 두고 있다가 똑같은 조건으로 실행되었을 때 함수의 코드를 모두 실행하지 않고 전에 기억해 둔 값을 반환하는 기술

  • 메모이제이션을 적용하는 대상이나 방식에 따라 코드는 달라질 수 있지만,
    결과를 저장해두고 재활용한다는 개념은 동일함
const cach = {}; // 함수의 반환 값을 저장하기 위한 변수

function square(n) {
  if (cache[n]) {
    return cache[n];
  }
  
  const result = n*n;
  cache[n] = result; // 다음에 저장된 값을 사용할 수 있도록 저장
  
  return result;
}

메모이제이션의 단점

  • 메모이제이션의 값을 저장하여 재활용하기 때문에 두 번째 실행부터 성능이 대폭 향샹된다는 장점,
  • 첫 번째 실행에는 여전히 느리다는 단점
  • 만약 항상 새로운 인자가 들어오는 함수는 메모이제이션을 적용해도 재활용할 수 있는 조건이 충족 되지 않기 때문에 오히려 메모리만 잡아먹는 골칫거리가 될 뿐임.

📌 해당 로직이 동일한 조건에서 충분히 반복 실행되는지 먼저 체크해야 함


이거 쓰려고 책샀음...
참고 서적:

 

LIST