Skip to content

FrontEnd 성능 개선기

KingDonggyu edited this page Dec 6, 2022 · 3 revisions

작성자 : 김동규

알림 페이지는 진재님이 SSE 작업 중이시니 끝나시면 연동하자..

통계 히스토그램 컴포넌트는 UI 구현했으니 승재님의 API 작업 완료되면 연동하면 되겠고..

그 동안 뭐하지???


라이트 하우스 한번 찍어보자!



성능 측정 항목 대부분의 시간이 너무 오래 걸리는 것을 발견..

사용자가 빠르게 콘텐츠를 인식할 수 있도록 성능 개선의 필요성을 느껴버렸다.

내 성격 상 절대 못지나치지. 개선해보자 🔥


BundleAnalyzerPlugin 웹팩 플러그인을 설치해서 번들 분석을 해봤다.

image



엥.. react-icons 너 뭐야..?

react-icons 라이브러리를 사용하여 애플리케이션에 적용한 아이콘은 단 두가지 밖에 없다.

그런데 쓸데없이 이만큼 차지하고 있다니..


1️⃣ react-icons 라이브러리를 @react-icons/all-files 라이브러리로 대체

react-icons는 icon 종류별로 구분되어 있으며, 종류별로 하나의 js 파일에 아이콘 전체를 포함하고 있다.

  • 따라서 빌드 시 해당 파일이 전체가 포함이 되기 때문에 번들 사이즈가 커지게 된다.

@react-icons/all-files 라이브러리는 아이콘 별로 js 파일을 가지고 있다.

  • 따라서 빌드 시 트리 쉐이킹 방식으로 인해 더 적은 크기의 번들을 만들게 된다.

다시 번들 분석해보자.

image



❗️ node_modules 번들 사이즈가 3.53 MB에서 1.27 MB로 줄었다!!

흠.. 그런데 메인 페이지에서는 사용하지도 않는 chart.js 등 라이브러리가 많은 크기를 차지하고 있다.


2️⃣ React의 lazySuspense를 사용하여 code splitting 적용

각 페이지들을 lazySuspense를 사용해 필요할 때만 불러오도록 했다.

const HomePage = lazy(() => import("@pages/HomePage"));
const ChallengePage = lazy(() => import("@pages/ChallengePage"));
const RecordPage = lazy(() => import("@pages/RecordPage"));
const ProfilePage = lazy(() => import("@pages/ProfilePage"));
const FollowPage = lazy(() => import("@pages/FollowPage"));
const LoginPage = lazy(() => import("@pages/LoginPage"));
const JoinPage = lazy(() => import("@pages/JoinPage"));
const StaticsPage = lazy(() => import("@pages/StaticsPage"));
const SearchPage = lazy(() => import("@pages/SearchPage"));

...

<Suspense fallback={<div>loading..</div>}>
  <Routes>
    {/* Home */}
    <Route path={RoutePath.HOME} element={<HomePage />} />
    <Route path={RoutePath.CHALLENGE} element={<ChallengePage />} />
    <Route path={RoutePath.RECORD} element={<RecordPage />} />
    {/* Search */}
    <Route path={RoutePath.SEARCH} element={<SearchPage />} />
    {/* Statics */}
    <Route path={RoutePath.STATICS} element={<StaticsPage />} />
    {/* Profile */}
    <Route path={RoutePath.PROFILE} element={<ProfilePage />} />
    <Route path={RoutePath.LOGIN} element={<LoginPage />} />
    <Route path={RoutePath.JOIN} element={<JoinPage />} />
    <Route path={RoutePath.SEARCH} element={<SearchPage />} />
    <Route path={RoutePath.FOLLOW} element={<FollowPage />} />
  </Routes>
</Suspense>

...


다시 번들 분석!!




위 번들에서 메인 페이지에 요청되는 번들은 index.js744.js 뿐! 훨씬 가벼워졌다.

❗️ 메인 번들인 index.js의 크기가 307.19 KB에서 10.2 KB로 확연히 줄어든 것을 볼 수 있다.


3️⃣ enum 문법 키워드를 전부 constunion type으로 변경

enum을 사용하면 번들 사이즈가 증가한다.

트리 쉐이킹이 되지 않기 때문이다!!

그래서 constunion type으로 전부 변경했다.

// constants/enum.ts

export enum RoutePath {
  HOME = "/",
  STATICS = "/statics",
  SEARCH = "/search",
  PROFILE = "/profile",
  CHALLENGE = "/challenge",
  RECORD = "/record",
  LOGIN = "/login",
  JOIN = "/join",
  FOLLOW = "/follow",
};

...

이랬던 코드를 아래와 같이!

// constants/enum.ts

export const RoutePath = {
  HOME: "/",
  STATICS: "/statics",
  SEARCH: "/search",
  PROFILE: "/profile",
  CHALLENGE: "/challenge",
  RECORD: "/record",
  LOGIN: "/login",
  JOIN: "/join",
  FOLLOW: "/follow",
} as const;
export type RoutePath = typeof RoutePath[keyof typeof RoutePath];

...

그 결과..



❗️ 메인 번들(index.js) 사이즈가 10.2 KB에서 7.79 KB로 줄었다!


4️⃣ 이미지 최적화

그럼 이 기세를 이어 이미지도 최적화해보자.

JPG, PNG 등 이미지 파일들을 WebP 파일로 변환하여 크기를 줄였다.

  • PIXLR 사이트에서 쉽게 변환할 수 있다.
  • 그래서 전부 수동으로 변경했다..

🏆 최종 결과



👍 전제 번들 사이즈가 3.83 MB에서 1.68 MB로 줄어들었다.

👍 홈 페이지 기준 메인 번들(index.js)이 307.14 KB에서 7.79 KB로 줄어들었다.

👍 Speed Index가 7.9 초에서 0.6 초로 줄어들었다.

👍 Total Blocking Time이 240 밀리초에서 130 밀리초로 줄어들었다.


아쉬운 점

Time to Interactive, Largest Contentful Paint 성능 요소는 크게 줄이지 못했다.

한번에 여러 데이터를 다른 API를 통해 각각 응답받기 때문에, 서버에서의 모든 데이터 응답 시간이 느려지는 요인이 큰 것 같다.

이 부분을 제외하고도 여러 문제점들을 분석하고 개선해보자! 🔥

💻 Projects

🤝 Rules

🎙️ Meeting

👾 Trouble Shootings

🛠 Tech Semina

🔰 초심자를 위한 기술 가이드

🏃‍♂️ Sprint

✏️ Reviews

💎 Mentoring

💬 Scrums

Week 1
Week 2
Week 3
Week 4
Week 5
Week 6
Clone this wiki locally