Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FE] 성능 개선 : bundle main.js 용량 줄이기 #787

Merged
merged 17 commits into from
Oct 24, 2024
Merged

Conversation

jinhokim98
Copy link
Contributor

issue

개선 이유

랜딩 페이지에서 필요하지 않은 스크립트를 제거해서 랜딩 페이지 초기 로딩 시에 자바스크립트 실행 시간을 줄이고 네트워크 요청량도 줄이는 효과를 얻고 싶었습니다.

현재 성능

npm run build를 했을 때는(g-zip 적용 전) 688KB가 나왔고, cloudfront에서 g-zip을 적용한 후 결과는 219KB이고 시간은 18ms가 걸렸습니다. 목표는 200KB 이하로 떨어뜨리는 것입니다.

코드 스플리팅

이미 코드 스플리팅이 적용되어있지만 하지만 페이지 추가된 컴포넌트에 스플리팅이 되어있지 않아서 추가로 랜딩 페이지에서 필요하지 않은 컴포넌트에 스플리팅을 적용했습니다.

추가로 생성된 페이지 컴포넌트에 lazy loading을 적용한 결과 28KB를 줄일 수 있었습니다.

랜딩 페이지에서 사용하지 않는 Tanstack-Query 분리

서버 상태 관리 라이브러리로 Tanstack-Query를 사용하고 있습니다. 하지만 랜딩 페이지에서는 백엔드 서버로 api 요청을 보내는 기능이 없습니다. 즉 랜딩 페이지에서는 Tanstack-Query가 필요하지 않은데 Tanstack-Query 관련 스크립트가 main에 포함되어있는 상황입니다. 그래서 이를 분리해서 백엔드 서버로 api를 요청하는 컴포넌트에서만 Tanstack-Query 스크립트를 불러오게 한다면 main을 더 줄일 수 있을 것 같아 진행했습니다.

개선 전 App 컴포넌트

const App: React.FC = () => {
  return (
    <HDesignProvider>
      <UnPredictableErrorBoundary>
        <Global styles={GlobalStyle} />
        <ErrorCatcher>
          <QueryClientBoundary>
            <ReactQueryDevtools initialIsOpen={false} />
            <NetworkStateCatcher />
            <ToastContainer />
            <AmplitudeInitializer>
              <Outlet />
            </AmplitudeInitializer>
          </QueryClientBoundary>
        </ErrorCatcher>
      </UnPredictableErrorBoundary>
    </HDesignProvider>
  );
};

export default App;

여기서 주목할 것은 ErrorCatcher와 QueryClientBoundary, ToastContainer입니다. 백엔드 서버로 api 요청 시 에러가 발생하면 QueryClientBoundary에서 error를 발생시키고 ErrorCatcher에서 이를 감지해서 Toast를 띄우는 기능입니다. 즉 이 세 개의 컴포넌트는 백엔드로 api를 요청하지 않는다면 필요 없는 컴포넌트입니다. 메인 페이지에서는 이 기능이 필요 없는데 프로젝트의 전반적으로 사용되는 코드에 포함되어있으니 비효율적이라고 판단. 이를 분리해보기로 했습니다.

EssentialQueryApp

const EssentialQueryApp: React.FC = () => {
  return (
    <ErrorCatcher>
      <QueryClientBoundary>
        <ReactQueryDevtools initialIsOpen={false} />
        <ToastContainer />
        <Outlet />
      </QueryClientBoundary>
    </ErrorCatcher>
  );
};

export default EssentialQueryApp;

Tanstack-Query를 사용해야하는 컴포넌트에서는 EssentialQueryApp 컴포넌트를 부르도록 분리했습니다. 그리고 EssentialQueryApp은 랜딩 페이지에서 필요하지 않은 컴포넌트이므로 동적 import를 적용시켜줬습니다.

서비스 전반적으로 필요한 컴포넌트는 최상단에서 불러주고 메인 페이지에는 EssentialQueryApp을 적용시키지 않았습니다.
그리고 그 외 페이지들은 백엔드로 api 요청을 날리므로 EssentialQueryApp을 적용시켜서 QueryClient가 필요한 컴포넌트에만 Tanstack-Query 스크립트가 포함되도록 변경했습니다.

import App from './App';
const EssentialQueryApp = lazy(() => import('./EssentialQueryApp'));

const router = createBrowserRouter([
  {
    path: '',
    element: (
      <Suspense>
        <App />
      </Suspense>
    ),
    children: [
      {
        index: true,
        path: ROUTER_URLS.main,
        element: <MainPage />,
      },
      {
        element: <EssentialQueryApp />,
        children: [
          {
            path: ROUTER_URLS.createEvent,
            element: <CreateEventFunnel />,
          },
          ....
        ],
      },
    ],
  },
]);

개선 결과

main에서 Tanstack-query 관련 기능을 분리한 결과 23KB를 추가로 감소시킬 수 있었습니다.

Tree Shaking

export default를 사용해서 export 하면 tree shaking이 제대로 적용되지 않는다고 합니다. 하지만 우리 코드에선 이미 export default가 많습니다. 다행히 Webpack의 Tree Shaking 공식문서를 보면 package.json에 sideEffects: false 속성을 추가하게 되면 webpack이 tree shaking을 할 때 사용하지 않는 export는 제거해도 괜찮다는 것을 webpack에 알려줄 수 있다고 합니다. 그래서 export default를 해주고 있어도 실제로 사용하지 않고 있다면 webpack이 tree shaking을 해주게 됩니다. 휴우..

Tree Shaking을 진행해준 결과 31KB를 추가로 감소시킬 수 있었습니다.

개선 결과

g-zip이 적용된 결과 main bundle을 보면 194KB이고 시간은 11ms가 측정됐습니다.
개선하기 전보다 bundle 크기는 219KB에서 194KB로 25KB를 줄였으며, 시간은 18ms에서 11ms로 7ms를 줄일 수 있었습니다.

🫡 참고사항

이번에도 위를 정리한 블로그 글을 첨부할게요.
https://jinokim.tistory.com/43

jinhokim98 and others added 5 commits October 18, 2024 15:25
* refactor: 랜딩 페이지 디렉토리 구조 변경

* refactor: nav 관련 스타일 nav로 이동

* remove: 사용하지 않는 컴포넌트 제거

* style: div => section, article 태그로 변경

* style: 컴포넌트 이름 조금 더 의미있게 변경
@jinhokim98 jinhokim98 added 🖥️ FE Frontend 🚧 refactor refactoring labels Oct 23, 2024
@jinhokim98 jinhokim98 added this to the v2.1.2 milestone Oct 23, 2024
@jinhokim98 jinhokim98 requested review from pakxe, soi-ha and Todari October 23, 2024 07:09
@jinhokim98 jinhokim98 self-assigned this Oct 23, 2024
@jinhokim98 jinhokim98 removed this from the v2.1.2 milestone Oct 23, 2024
@jinhokim98 jinhokim98 linked an issue Oct 23, 2024 that may be closed by this pull request
2 tasks
* feat: 문의하기 구글 forms 페이지 링크 연결

* fix: chromatic 에러 해결
@jinhokim98 jinhokim98 changed the title [FE] main.js 용량 줄이기 [FE]성능 개선 : bundle main.js 용량 줄이기 Oct 23, 2024
@jinhokim98 jinhokim98 changed the title [FE]성능 개선 : bundle main.js 용량 줄이기 [FE] 성능 개선 : bundle main.js 용량 줄이기 Oct 23, 2024
soi-ha and others added 11 commits October 23, 2024 16:26
* refactor: 성능개선 Preconnect to requered origins (font)

* fix: storybook에서 pretendard 폰트가 적용되도록 스토리북 preview.tsx 수정
* feat: intersection api를 이용해서 특정 영역이 관측될 때 이미지 src를 채우는 hook 구현

* feat: useImageLazyLoading 훅 적용

* feat: 이미지 alt 값을 한국말로 변경

* fix: feature4,5 이미지를 4 불러올 때 한 번에 불러오는 방식으로 변경

* feat: threshold를 0.1에서 0.05로 조금 더 빨리 불러오도록 변경

* feat: alt 행댕이를 행댕이 - 행동대장 마스코트 라고 자세하게 설명

* feat: threshold default value 0.1 -> 0.05로 변경

* feat: 0.1 -> 0.05 놓친 부분 수정
* feat: Kakao script 동적으로 불러올 수 있는 함수 작성

* feat: 드롭다운 버튼 베이스 onClick 메서드 추가

* feat: 모바일 환경에서 초대버튼 눌렀을 때 카카오 스크립트를 불러오도록 설정

* feat: KakaoInitializer 제거
* feat: 랜딩페이지 개선

* fix: 첫 스크롤이 이상하게 되던 오류 수정

* design: image가 꽉차게 보이도록 변경

* move: CreatorSection 파일 위치 변경

* fix: IOS 환경에서 svg 렌더를 위해 object tag 로 변경

* fix: import 잘못된 오류 수정

* style: lint 적용

* fix: `useMainPageYScroll.ts`를 FeatureSection 내부에서 호출하도록 변경

* refactor: avatar style 분ㄹ

* fix: avatar를 button이 아니라 a태그로 감싸도록 변경

* style: lint 적용 및 사용하지 않는 주석과 코드 제거

* refactor: Avatar 부분 리스트 렌더링으로 변경

* style: fix 적용

* fix: object tag에 alt property 제거
* feat: 랜딩페이지 개선

* fix: 첫 스크롤이 이상하게 되던 오류 수정

* design: image가 꽉차게 보이도록 변경

* move: CreatorSection 파일 위치 변경

* fix: IOS 환경에서 svg 렌더를 위해 object tag 로 변경

* fix: import 잘못된 오류 수정

* style: lint 적용

* chore: webp포맷의 이미지 추가

* chore: webp타입 추가

* feat: 이미지 호스팅 경로를 생성하는 함수 구현

* feat: src, fallbackSrc를 지정해 대체 이미지를 보여줄 수 있는 Image 컴포넌트 구현

* feat: Image컴포넌트를 사용해 이미지를 불러오도록 수정

* feat: Avatar 컴포넌트에서 이미지 경량화를 위한 Image 컴포넌트를 사용

* chore: 사용하지 않고있는 토스 아이콘 제거

* feat: 용량 큰 이미지를 사용하는 곳에선 webp이미지를 사용하도록 수정

* feat: 이미지 경로를 받아오는 함수가 svg포맷도 받아들일 수 있도록 수정

* fix: 이미지 크기가 넘쳐버리지 않도록 width 속성 추가

* feat: 은행 목록 이미지를 webp로 이미지 호스팅 서버에서 가져오도록 수정

* chore: 사용하지 않는 이미지 제거

* feat: 흔듯콘을 webp로 불러오도록 함

* fix: 흔듯콘에 width부여

* design: 행동개시 행댕이의 크기가 너무 커지지 않도록 maxWidth 속성 추가

---------

Co-authored-by: 이태훈 <[email protected]>
* fix: DropDown에 Tap 글씨가 위에 있는 에러 수정

* feat: QR코드로 초대하기 페이지 디자인 구현 및 navigate 추가

* feat: qrcode.react 라이브러리를 활용하여 행사 접속 QR코드 생성 구현

* feat: 데스크탑 초대하기를 DropDown으로 변경하여 QR코드 초대 기능 추가하기
@jinhokim98 jinhokim98 changed the base branch from fe-dev-v2.1.2 to fe-dev October 23, 2024 12:37
@woowacourse-teams woowacourse-teams deleted a comment from github-actions bot Oct 23, 2024
Copy link

@jinhokim98 jinhokim98 added this to the v2.1.3 milestone Oct 24, 2024
Copy link
Contributor

@soi-ha soi-ha left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

용량이 정말 많이 줄었네요! 최고에요 쿠키~!

@@ -3,6 +3,13 @@
"version": "1.0.0",
"description": "",
"type": "module",
"sideEffects": [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이건 또 처음 알았네요!
쿠키 덕분에 새로운거 또 알고 갑니댜~

Copy link
Contributor

@Todari Todari left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

최적화의 신.... 고생했어요

@Todari Todari merged commit a0b424e into fe-dev Oct 24, 2024
2 checks passed
@Todari Todari deleted the feature/#785 branch October 24, 2024 09:10
@Todari Todari mentioned this pull request Oct 24, 2024
Todari added a commit that referenced this pull request Oct 24, 2024
* refactor: 랜딩 페이지 디렉토리 구조 변경 (#767)

* refactor: 랜딩 페이지 디렉토리 구조 변경

* refactor: nav 관련 스타일 nav로 이동

* remove: 사용하지 않는 컴포넌트 제거

* style: div => section, article 태그로 변경

* style: 컴포넌트 이름 조금 더 의미있게 변경

* refactor: App을 제외한 페이지 컴포넌트 lazy loading

* refactor: QueryClient가 필요하지 않은 랜딩 페이지에서 tanstack-query script 제거

* refactor: tree shaking을 deep하게 적용하기 위해 package.json에 sideEffects false 적용

* feat: prod build 파일에서 sourcemap과 license 파일 제거

* feat: 문의하기 페이지 구현 (#772)

* feat: 문의하기 구글 forms 페이지 링크 연결

* fix: chromatic 에러 해결

* refactor 성능 개선 : Preconnect to requered origins (#771)

* refactor: 성능개선 Preconnect to requered origins (font)

* fix: storybook에서 pretendard 폰트가 적용되도록 스토리북 preview.tsx 수정

* refactor: 성능 개선 : 랜딩 페이지 이미지를 필요한 만큼만 불러오기 (#774)

* feat: intersection api를 이용해서 특정 영역이 관측될 때 이미지 src를 채우는 hook 구현

* feat: useImageLazyLoading 훅 적용

* feat: 이미지 alt 값을 한국말로 변경

* fix: feature4,5 이미지를 4 불러올 때 한 번에 불러오는 방식으로 변경

* feat: threshold를 0.1에서 0.05로 조금 더 빨리 불러오도록 변경

* feat: alt 행댕이를 행댕이 - 행동대장 마스코트 라고 자세하게 설명

* feat: threshold default value 0.1 -> 0.05로 변경

* feat: 0.1 -> 0.05 놓친 부분 수정

* refactor: 성능 개선 : Kakao script를 필요한 곳에서 다운로드 받기 (#776)

* feat: Kakao script 동적으로 불러올 수 있는 함수 작성

* feat: 드롭다운 버튼 베이스 onClick 메서드 추가

* feat: 모바일 환경에서 초대버튼 눌렀을 때 카카오 스크립트를 불러오도록 설정

* feat: KakaoInitializer 제거

* refactor: v2.1.1에서 구현한 랜딩페이지 개선 (#777)

* feat: 랜딩페이지 개선

* fix: 첫 스크롤이 이상하게 되던 오류 수정

* design: image가 꽉차게 보이도록 변경

* move: CreatorSection 파일 위치 변경

* fix: IOS 환경에서 svg 렌더를 위해 object tag 로 변경

* fix: import 잘못된 오류 수정

* style: lint 적용

* fix: `useMainPageYScroll.ts`를 FeatureSection 내부에서 호출하도록 변경

* refactor: avatar style 분ㄹ

* fix: avatar를 button이 아니라 a태그로 감싸도록 변경

* style: lint 적용 및 사용하지 않는 주석과 코드 제거

* refactor: Avatar 부분 리스트 렌더링으로 변경

* style: fix 적용

* fix: object tag에 alt property 제거

* fix: 이벤트 홈 페이지에 있을 땐 토큰이 있어도 지출 상세로 접근 불가하도록 수정 (#781)

* fix: cypress에서는 sideEffects를 tree shaking하지 않음

* refactor: 성능 개선 : Serve images in next-gen formats  (#784)

* feat: 랜딩페이지 개선

* fix: 첫 스크롤이 이상하게 되던 오류 수정

* design: image가 꽉차게 보이도록 변경

* move: CreatorSection 파일 위치 변경

* fix: IOS 환경에서 svg 렌더를 위해 object tag 로 변경

* fix: import 잘못된 오류 수정

* style: lint 적용

* chore: webp포맷의 이미지 추가

* chore: webp타입 추가

* feat: 이미지 호스팅 경로를 생성하는 함수 구현

* feat: src, fallbackSrc를 지정해 대체 이미지를 보여줄 수 있는 Image 컴포넌트 구현

* feat: Image컴포넌트를 사용해 이미지를 불러오도록 수정

* feat: Avatar 컴포넌트에서 이미지 경량화를 위한 Image 컴포넌트를 사용

* chore: 사용하지 않고있는 토스 아이콘 제거

* feat: 용량 큰 이미지를 사용하는 곳에선 webp이미지를 사용하도록 수정

* feat: 이미지 경로를 받아오는 함수가 svg포맷도 받아들일 수 있도록 수정

* fix: 이미지 크기가 넘쳐버리지 않도록 width 속성 추가

* feat: 은행 목록 이미지를 webp로 이미지 호스팅 서버에서 가져오도록 수정

* chore: 사용하지 않는 이미지 제거

* feat: 흔듯콘을 webp로 불러오도록 함

* fix: 흔듯콘에 width부여

* design: 행동개시 행댕이의 크기가 너무 커지지 않도록 maxWidth 속성 추가

---------

Co-authored-by: 이태훈 <[email protected]>

* feat: QR코드로 초대하기 기능 추가 (#783)

* fix: DropDown에 Tap 글씨가 위에 있는 에러 수정

* feat: QR코드로 초대하기 페이지 디자인 구현 및 navigate 추가

* feat: qrcode.react 라이브러리를 활용하여 행사 접속 QR코드 생성 구현

* feat: 데스크탑 초대하기를 DropDown으로 변경하여 QR코드 초대 기능 추가하기

---------

Co-authored-by: Soyeon Choe <[email protected]>
Co-authored-by: TaehunLee <[email protected]>
Co-authored-by: Pakxe <[email protected]>
Co-authored-by: 이태훈 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🖥️ FE Frontend 🚧 refactor refactoring
Projects
Status: ✅ Done
Development

Successfully merging this pull request may close these issues.

[FE] 성능 개선 : bundle main.js 용량 줄이기
4 participants