회사에서 제작한 청소년 금연 관련 admin을 리팩토링 하는 과정에서 light house 지표 성능 최적화를 진행해보고 싶어졌습니다.
최적화를 진행하기 전 성능 지표는 61점으로 낮은 수준으로 LCP와 FCP가 각각 3.4초인 것을 확인할 수 있었습니다.
LCP(Largest Contentful Paint, 최대 콘텐츠풀 페인트)란?
로딩 성능을 측정하는 지표로서, 사용자가 웹 페이지를 로드할 때 뷰포트 내에 있는 가장 큰 이미지 또는 텍스트 블록이 브라우저 화면에서 얼마나 빨리 렌더링 되는지 측정하는 지표이다.
좋은 사용 경험을 제공하기 위해서는 페이지가 처음으로 로딩된 후 2.5초 이내에 LCP 가 발생해야 한다.
FCP(First Contentful Paint)란?
첫 번째 콘텐츠가 렌더링 되기 시작하는 시점을 측정하는 지표
LCP는 주로 하기 4가지 요인에 의해 영향을 받는다고 합니다.
코드 스플리팅은 큰 번들을 여러 작은 청크(chunk)로 분할하는 프로세스입니다. 이는 초기 로딩 속도를 개선하는 데 도움을 줍니다. React.lazy()는 동적 import를 사용하여 컴포넌트를 로드합니다. 동적 import를 사용하면 컴포넌트를 비동기적으로 로드할 수 있습니다.
const Component = React.lazy(() => import('./Component'));
function App() {
return (
<div>
{/* Suspense 컴포넌트로 Component를 감싸고, 로딩 중에 표시할 UI를 정의합니다. */}
<React.Suspense fallback={<div>loading</div>}>
<Component />
</React.Suspense>
</div>
);
}
export default App;
router에 정의된 대시보드 컴포넌트를 모두 lazy Loading을 이용해 코드 스플리팅을 진행하였고, LCP가 3.4초에서 2.7초로, FCP 또한 3.4초에서 2.5초로 줄어든 것을 확인할 수 있었습니다.
yarn-deduplicate 명령어를 통해 번들 사이즈를 줄일 수 있습니다.
구글 light house 지표가 자바스크립트 번들에 존재하는 중복모듈이 3KiB이라고 알려주고 있습니다. (1 키비바이트는 1.024 킬로바이트이다.)
// yarn-deduplicate 설치
$ yarn global add yarn-deduplicate
// cd 프로젝트_경로
$ yarn-deduplicate yarn.lock
적용하고 청크파일에서 3KiB가, yarn.lock
파일에서 1601줄의 코드가 줄어든 것을 확인할 수 있었습니다.
yarn-deduplicate 참고 글
yarn global 실행 시 command not found 해결 방법
기존에는 Google Fonts를 이용해 웹폰트를 호스팅하였는데 @fontsource npm 패키지로 웹폰트를 직접 호스팅하면, 웹폰트 다운로드로 인한 지연을 최소화하여 LCP와 FCP 지표를 향상 시킬 수 있습니다.
$ yarn add @fontsource/public-sans
모든 컴포넌트에서 다운 받은 웹 폰트를 이용할 수 있도록 import 문을 최상위 컴포넌트에서 위치시켜줍니다.
프로젝트에서 사용하는 글꼴 굵기와 스타일만 명시하여 불러와 최적화를 진행할 수 있습니다.
// src/App.tsx
import '@fontsource/public-sans/400.css';
import '@fontsource/public-sans/500.css';
import '@fontsource/public-sans/600.css';
import '@fontsource/public-sans/700.css';
로고 이미지를 2x 크기로 최적화하고, png 파일을 구글에서 권장하는 확장자인 webp으로 변환하여 LCP 50 밀리초를 개선했습니다.
프로젝트 내의 미사용 코드를 찾기 위해 ts-prune
을 설치해줍니다.
// 설치
$ yarn add -D ts-prune
// used in module인 부분과 default export로 사용된 부분을 제외하고 출력
$ npx ts-prune | grep -E -v '(used in module)|default'
ESM(ES Module)내에서 사용하지 않는 변수, 함수들을 확인할 수 있으며 데드 코드를 삭제하는 과정을 거쳤습니다.
해당 다섯가지 최적화를 진행하고 성능 지표는 61점 => 75점, LCP는 3.4초 => 2.4초, FCP는 3.4초 => 2.1초, Speed Index도 3.4초 => 2.1초로 개선된 것을 확인할 수 있었습니다.
LCP가 2.5초 아래로 줄어든 것은 유의미한 변화라고 생각하며 아직 성능 지표가 75점으로 아쉬운 수준이라, 추가적으로 최적화할 수 있는 방법을 찾아보려고 합니다.