일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- CDN
- typescript
- react
- route
- 성능최적화
- 회고
- sequelize
- component
- styled-component
- 반응형웹
- cicd
- scrapping
- 정규표현식
- go
- Modal
- 웹크롤링
- npx
- docker
- Recoil
- javascript animation
- Redux
- AWS
- socket.io
- 포트포워딩
- express
- 웹팩
- graphql
- Today
- Total
프로그래밍 공부하기
웹 성능 최적화 - Code Split 본문
웹 로딩 속도는 고객 경험에 매우 중요한 요소이다. KissMetrics 연구에 의하면 47%의 소비자는 웹 페이지가 2초 이내에 로드되기를 기대하며 3초가 되면 40%의 소비자가 웹 페이지를 이탈한다고 한다. 기사에 의하면 웹 로딩 속도 1초가 빨라지면 아마존 판매량이 1%증가 한다고 한다.
개발자가 웹 성능을 높이는 방법은 무엇일까? 우선 웹 성능 결정요소는 크게 로딩 성능과 렌더링 성능으로 나뉜다. 로딩 성능은 필요한 리소스를 불러오는 것이고 렌더링 성능은 불러온 리소스를 화면에 보여주는 것이다. 이 글에선 로딩 성능을 최적화하는 Code Split을 해보려 한다.
1. 페이지 분석
최근 프로젝트인 땅땅마켓의 Search페이지에서 개발자 도구의 퍼포먼스 탭을 이용하여 분석해보았다. 그 결과 지금 당장 필요하지 않은 모듈까지 해당 페이지에서 불러오고 있는 것을 알 수 있었다. bundle-analyzer도 한 번 분석해보자.
React를 빌드하면 WebPack은 비슷한 파일을 묶는 Bundling을 수행한다. 웹 페이지는 번들링된 결과 단위로 코드를 불러온다. 그런데 번들링 결과가 너무 크다면 페이지 접속 시 소스 코드를 불러오는데 오랜 시간이 걸린다.
위 사진은 cra-bundle-analyzer를 이용하여 프로젝트를 분석한 결과의 일부이다. main.chunk라는 번들에 64개의 모듈이 함께 들어있는 것을 확인할 수 있다. 즉, index.tsx를 보여주기위해 당장 필요하지 않은 RegisterForm, FilterBtn 등의 모듈들을 함께 불러오므로 웹 로딩 시간이 느려질 수밖에 없다.
2. React lazy, preload
페이지에서 당장 필요하지 않은 대표적인 모듈은 모달이다. 모달은 숨겨져 있다가 사용자가 특정 컨텐츠를 선택했을 때에 비로소 필요해지기 까닭이다. 즉, 페이지를 로드할 때 꼭 필요한 모듈은 아니다. 이 부분을 Code Split 해보자
import React, {Suspense, lazy} from 'react';
const Modal = lazy(() => import('../Modal/index'));
const ItemDetail = lazy(() => import('./ItemDetail'));
const ItemCard: React.FC<Props> = ({item}) => {
//생략..
return (
<>
<Suspense fallback={<div>로딩중...</div>}>
<Modal visible={isOpenPopup} closeCb={closePopUp} className={'sidemodal'}>
<ItemDetail item={item} requestBid={requestBid}></ItemDetail>
</Modal>
</Suspense>
{/*생략...*/}
</>
);
};
React에서 Code Split을 하기 위해 Suspense, lazy 가 필요하다. lazy는 늦게 모듈을 import 하기 위함이고 Suspense는 해당 모듈이 import 되지 않았을 때 대신 보여줄 요소를 의미한다. 이렇게 하면 위 컴포넌트를 로드할 때 Modal과 ItemDetail은 함께 로드되지 않고, 해당 컴포넌트가 필요할 때 로드를 시작한다.
import React, {Suspense, lazy, useEffect} from 'react';
const Modal = lazy(() => import('../Modal/index'));
const ItemDetail = lazy(() => import('./ItemDetail'));
const ItemCard: React.FC<Props> = ({item}) => {
//생략..
useEffect(() => {
import('../Modal/index');
import('./ItemDetail');
}, []);
return (
<>
<Suspense fallback={<div>로딩중...</div>}>
<Modal visible={isOpenPopup} closeCb={closePopUp} className={'sidemodal'}>
<ItemDetail item={item} requestBid={requestBid} ></ItemDetail>
</Modal>
</Suspense>
{/*생략...*/}
</>
);
};
그런데 모달의 내용이 너무 많거나 용량이 커서 미리 로드하는 것이 나을 수도 있다. 이 때는 개발자가 별도로 모달을 미리 로드하는 것이 좋다. 위 코드는 ComponentDidMount 후에 Modal과 ItemDetail을 미리 로드하는 코드이다. 이렇게 하면 위 컴포넌트(Search)와 모달을 분리하면서도 사용자 경험을 해치지 않는다.
이 외에 Code Split을 하기 좋은 장소는 라우트이다. A페이지에 있다면 B페이지의 요소들과는 상호작용할 일이 없기 때문이다. 이 부분들도 위와 같은 방식으로 lazy-pre load를 할 수 있다.
3. 결과
Code Split 결과 index.tsx + 64 modules 였던 번들이 index.tsx + 26 modules로 변경되었다. 퍼포먼스 탭에서도 서치 페이지에서 ItemDetail을 불러오지 않는 것을 확인하였다.
React.lazy, Suspense를 쓸 때 주의할 점은 서버 사이드 렌더링을 지원하지 않는다는 점이다. 서버 사이드 렌더링을 한다면 Loadable Components를 사용하는 것이 좋다.
'Web > [JS] FrontEnd' 카테고리의 다른 글
webpack (0) | 2021.05.19 |
---|---|
Recoil (0) | 2021.05.12 |
Responsive Web (0) | 2021.05.06 |
Redux ducks 패턴 with Typescript (0) | 2021.04.30 |
웹페이지 반응속도측정 사이트 (0) | 2021.04.27 |