본문 바로가기

리액트

[Vite] Bundle 사이즈 최적화 하기

평화롭게 개발을 하던 어느날...

 

vite 경고

빌드를 돌렸는데 Vite가 노란색으로 읽고 싶게 경고를 주었다.

500kb가 넘는 chunk가 있으니 코드 스플리팅을 하라는 친절한(?) 경고였다.

 

번들 크기가 1.7MB라 생각보다 크기도 하고, 성능 측정도 해볼겸 번들 사이즈를 줄여보기로 했다!

 

 

1. 현재 번들 크기 확인하기

빌드 했을 때 나온 번들 크기가 정확하게 어떻게 되고 있는지 확인해보기 위해 rollup-plugin-visualizer를 이용하여 확인해보기로 했다.

 

yarn add -D rollup-plugin-visualizer

yarn build

 

//vite.config.ts

import { visualizer } from "rollup-plugin-visualizer";

...

export default defineConfig({
  plugins: [
    ...
    visualizer({
      filename: './dist/report.html',
      open: true,
    })
  ],
  ...
});

 

후에 빌드를 해보면..

 

이렇게 사진이 출력 되었다!

이제 하나씩 번들을 줄여보자..!

 

 

2. lodash 최적화

 

줄여야 할 게 여러개가 있지만 일단 먼저 lodash 라이브러리 부터 최적화를 해보려고 한다.

내 프로젝트에서는 loadsh에서 debounce 함수만 사용하고 있는데 번들 크기가 무려 547kb를 잡고 있다..

 

import _ from 'lodash';

...

const InfoHeader = ({ streamerName, streamerProfileImage, chUrl }: Props) => {
  const onClick = _.debounce((e: MouseEvent<HTMLDivElement>) => {
   ...
  }, 800);
  return (
    <div
      data-testid="streamer-info-container"
      onClick={onClick}
      className="flex cursor-pointer items-center">
      ...
    </div>
  );
};

export default InfoHeader;

 

위 처럼 사용 중이라서 그런데 lodash 자체를 로드해서 그런가보다.

나는 debounce 함수 밖에 사용하고 있지 않아서 이를 최적화를 진행해보자!

 

import debounce from 'lodash/debounce';

...

const InfoHeader = ({ streamerName, streamerProfileImage, chUrl }: Props) => {
  const onClick = debounce((e: MouseEvent<HTMLDivElement>) => {
   ...
  }, 800);
  return (
    <div
      data-testid="streamer-info-container"
      onClick={onClick}
      className="flex cursor-pointer items-center">
      ...
    </div>
  );
};

export default InfoHeader;

 

import를 위와 같이 변경 후에 빌드해보면..

 

lodash 최적화 후 결과

 

1.73mb -> 1.65mb 로 줄어든 것을 볼 수 있다.

게다가 이미지상에서 크게 한 곳을 차지하던 lodash도 사라졌다..

 

 

3. Rollup의 manualChunks 옵션을 사용하여 청크를 수동으로 분할

 

그러나 아직 큰 번들을 차지하는 라이브러리가 두 개가 더 있다.

하나를 크게 로드하는 것 보다 작은 파일을 분할해서 로드하는게 나을 것 같다고 판단해서 위 두 파일도 별도의 chunk로 분할하려 한다.

 

분할시키는 방법은 rollup의 manualChunks 옵션을 사용하는 것인데 하나의 번들을 수동으로 분할 시키는 옵션이다.!

 

//vite.config.ts

import { visualizer } from "rollup-plugin-visualizer";

...

export default defineConfig({
    build: {
    rollupOptions: {
      output: {
        manualChunks: (id: string) => {
          if (
            id.includes('node_modules/react/') ||
            id.includes('node_modules/react-dom/') ||
            id.includes('node_modules/react-router-dom/')
          ) {
            return '@react-vendor';
          }
          if (id.includes('node_modules/onnxruntime-web/')) {
            return '@onnxruntime-web-vendor';
          }
          if (id.includes('node_modules/lottie-web/')) {
            return '@lottie-web-vendor';
          }
        },
      },
    },
  },
  ...
});

 

이렇게 react, react-dom, react-router-dom등과 같이 잘 변경되지 않는 라이브러리는 하나로 묶어 번들을 관리하게 되면 별도 chunk로 분리하여 크기적 이점을 가져갈 수 있고, 다른 큰 번들 또한 분리시켜서 작게 분할할 수 있다.

 

 

 

 

이렇게 1.65MB 정도의 파일을 다른 4개의 파일들로 분할해서 더 작은 파일들로 로드하도록 변경하였다.

 

위에서 설명한 전략들을 잘 활용한다면 애플리케이션의 성능상 이점을 가져갈 수 있을 것 같다.

하지만 manualChunks 옵션을 잘못 활용하게될 경우 애플리케이션 자체가 실행이 안될 수 있으므로 주의해서 사용하자!