줍줍 프로젝트 성능최적화 이야기

kkojae·2022년 10월 23일
2
post-thumbnail

줍줍 프로젝트는 슬랙 메시지를 아카이빙하는 서비스입니다.
프로젝트 github

줍줍은 랜딩 페이지와 메시지 피드 페이지에서 사용자 렌더링 속도 개선을 목표로 성능 최적화를 진행했습니다.

성능 개선 전 문제사항

줍줍의 성능 개선 전 성능 측정 결과를 보면 아래와 같습니다.

랜딩 페이지 webpagetest 성능지표

WebPageTest 에서  Paris - EC2 Chrome Network Fast 3G 환경 기준으로 LCP 점수를 측정 했을때 첫번째 로드시 7.129s, 두번째 이후 로드 시 5.586s 이 측정되어서,

  1. 브라우저가 요청하는 리소스 사이즈 절감
  2. 캐싱 정책 수립하여 적용

이 필요했습니다.

성능 개선 전 성능 지표

메시지 피드 페이지의 lighthouse 성능지표

desktop

mobile

줍줍은 모바일 유저를 타겟으로 하고 있습니다.

라이트하우스의 모바일 성능 점수가 47점으로 측정 되어서, 모바일 라이트하우스의 성능 점수를 80점 이상으로 올리는 것을 목표로 설정했습니다.

또한 라이트하우스에서 제안한 성능 개선 방법에는

  1. 리소스 크기 절감
  2. 캐싱 정책 수립

이 있어서, 이를 적용하여 라이트하우스의 성능 점수를 개선하는 것을 목표로 설정했습니다.

성능 최적화 대상

1. 리소스 크기 절감 - 자바스크립트 번들 사이즈

성능 최적화 이전에 코드 스플릿팅을 적용 해두었기 때문에 자바스크립트 번들 사이즈는 생각보다 크지 않았지만, gzip 압축 을 사용하여 리소스 크기를 더 절감하는 것을 목표로 했습니다.

2. 리소스 크기 절감 - font

폰트는 Roboto 와 TwayAir 를 사용하고 있었고, 폰트 확장자는 woff를 사용했습니다.

하지만 정적파일로 프로젝트에서 사용되지 않는 폰트들도 가지고 있었기 때문에, 불필요한 assets 파일 제거, 폰트 확장자 변경, 서브셋 폰트 사용 등의 방법으로 최적화를 목표로 했습니다.

const GlobalStyle = createGlobalStyle<{ theme: Theme }>`
  @font-face {
    font-family: 'Roboto';
    font-weight: 300;
    src: url(${RobotoLightWoff}) format('woff');
  }

  @font-face {
    font-family: 'Roboto';
    font-weight: 300;
	font-style: italic;
    src: url(${RobotoLightItalicWoff}) format('woff');
  }

  @font-face {
    font-family: 'Roboto';
    font-weight: 400;
    src: url(${RobotoRegularWoff}) format('woff');
  }

  @font-face {
    font-family: 'Roboto';
    font-weight: 400;
	font-style: italic;
    src: url(${RobotoRegularItalicWoff}) format('woff');
  }
  
  @font-face {
    font-family: 'Roboto';
    font-weight: 600;
    src: url(${RobotoBoldWoff}) format('woff');
  }

  @font-face {
    font-family: 'Roboto';
    font-weight: 600;
	font-style: italic;
    src: url(${RobotoBoldItalicWoff}) format('woff');
  }

  @font-face {
    font-family: 'Twayair';
    src: url(${TwayairWoff}) format('woff');
  }
	
	// some code ...
`;

3. 리소스 크기 절감 - svg

기존 프로젝트에서 아이콘으로 사용되는 svg 파일은 15개였으며, 모든 svg 파일에 대하여 네트워크 요청을 하다보니 불필요하게 네트워크 요청이 많았습니다.

4. 리소스 크기 절감 - 프로필 이미지

기존 프로젝트에서 서버로부터 받는 프로필 이미지의 크기는 512px x 512px 이었습니다.

하지만, 실제로 프론트엔드에서 프로필이미지로서 사용되는 이미지의 크기는 35px x 35px 이었기 때문에 불필요하게 큰 사이즈의 이미지를 요청하여 네트워크 요청의 비용을 낭비하고 있습니다.

5. 캐싱

캐싱 정책을 설정하지 않아서, 각 브라우저의 브라우저 캐시를 사용하고 있습니다. 브라우저 캐시를 컨트롤 해주지 않을 경우 리소스가 변경되어도 사용자의 브라우저 캐시를 비워줄 수 없는 문제가 발생하고, 브라우저마다 디폴트 캐싱 기간이 다르기 때문에 동일한 업데이트를 해줄수 없는 문제가 발생할 수 있습니다.

성능 최적화 방법

1. 리소스 크기 절감 - font

const GlobalStyle = createGlobalStyle<{ theme: Theme }>`
  @font-face {
    font-family: 'Roboto';
    font-weight: 300;
		font-display: swap;
    src: url(${RobotoLightWoff2}) format('woff2'), url(${RobotoLightWoff}) format('woff'), url(${RobotoLightTtf}) format('truetype');
  }

  @font-face {
    font-family: 'Roboto';
    font-weight: 400;
		font-display: swap;
    src: url(${RobotoRegularWoff2}) format('woff2'), url(${RobotoRegularWoff}) format('woff'), url(${RobotoRegularTtf}) format('truetype');
  }
  
  @font-face {
    font-family: 'Roboto';
    font-weight: 600;
		font-display: swap;
    src: url(${RobotoBoldWoff2}) format('woff2'), url(${RobotoBoldWoff}) format('woff'), url(${RobotoBoldTtf}) format('truetype');
  }

  @font-face {
    font-family: 'Twayair';
		font-display: swap;
    src: url(${TwayairWoff2}) format('woff2'), url(${TwayairWoff}) format('woff'), url(${TwayairTtf}) format('truetype');
  }
	
	// some code ...
`;
  • 불필요한 font 파일을 제거하여 리소스 및 네트워크 요청 비용을 절감했습니다.
  • Roboto 폰트는 preload를 할 수 있도록 설정해 보다 빠르게 프로젝트의 메인 폰트를 다운로드하여 사용자에게 폰트가 적용된 화면을 제공할 수 있도록 했습니다.
  • 또한, 서브셋 폰트를 적용해 실제로 사용되지 않는 글자를 제거해 보다 더 가벼운 폰트를 적용했습니다.
  • woff2, woff, ttf 폰트를 각각 설정함으로써 폰트 용량을 절감하여 폰트 다운로드 속도를 개선하고, 구형 브라우저 지원을 했습니다.

2. 리소스 크기 절감 - svg

import { SVGProps } from "react";

function ArrowIconDown({ width, height, fill }: SVGProps<SVGAElement>) {
  return (
    <svg
      width={width}
      height={height}
      viewBox="0 0 24 24"
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path
        d="M7.41 8.57999L12 13.17L16.59 8.57999L18 9.99999L12 16L6 9.99999L7.41 8.57999Z"
        fill={fill}
      />
    </svg>
  );
}

export default ArrowIconDown;
  • 기존에 svg 파일로 일일이 저장하고 있던 아이콘 파일들을 컴포넌트화하여 사용함으로써, 별도의 네트워크 요청을 보내지 않도록 최적화 했습니다.

3. 리소스 크기 절감 - gzip 적용

  • gzip, code spliting, chunk file 분리를 통해 기존의 367kb → 13.9kb 로 자바스크립트 번들 사이즈를 압축했습니다.

4. 리소스 크기 절감 - 프로필 이미지

  • 서버에서 받아오는 프로필 이미지의 크기를 35px x 35px 과 가장 가까운 크기인 48px x 48px 로 변경하여 불필요하게 큰 이미지 요청에 대한 네트워크 요청 낭비를 절감했습니다.

5. 캐싱

max-age=1년으로 설정 이유

  • CDN서버를 따로 두고 있지 않기 때문에 브라우저 캐시 기능을 사용하기로 했고, 캐시 버스팅을 통해 정적파일이 변경되었을 경우 변경된 정적 파일을 제공할 수 있도록 설정했습니다.
  • index.html의 경우 max-age=0을 설정해줬는데, html 파일의 경우 캐시 버스팅 기능을 사용할 수 없기 때문에 브라우저 캐시 기능을 사용하지만, 매번 재검증을 통해 변경된 부분이 있다면 변경된 html 파일로 변경할 수 있도록 설정했습니다.

성능 개선 후 성능 지표

LCP 점수


webpagetest

라이트하우스 점수

데스크탑

모바일

이상으로 줍줍 프로젝트 성능최적화에 대한 이야기를 마무리 하려합니다.

0개의 댓글