Lighthouse를 활용한 Tree Shaking(with Build)
Tags: webdev, javascript, react, vite
Published: 2024-05-21 12:47:17

프로젝트를 마치고 Build를 진행하고 나서 다음과 같은 결과가 나왔다.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3o0ql0xbroa9h9w65e1r.png)

흠... 좋은데? 🤦‍♂️

빌드된 파일도 크고 빌드 시간도 길다. 이를 해결하는 과정을 진행해 보자.

마침 Lighthouse를 통해 LCP 시간을 줄이고 있는데 Treemap을 활용해서 Tree Shaking을 진행해보고 싶었다.

> Lighthouse 탭에서 스크롤을 내리다 보면 `View Treemap` 버튼이 있다.

아래 사진을 보면 빌드된 각 파일의 크기를 알 수 있다.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lmqnzj4g8oczx4gnsigt.png)

- @mui/icons-material
- @mui-material
- firebase/firestore
- devs/chunk
- react-dom
- ...

&nbsp;

## 라이브러리 경량화1 (MUI)

필자는 프로젝트에 [mui](https://mui.com/) 를 사용하였다. 그런데 거의 대부분 컴포넌트 및 파일에서 모듈 전체 멤버를 import하여 필요한 컴포넌트를 불러와 사용하였다.

당시에는 몰랐지만 `import { AbcRounded } from '@mui/icons-material'` 처럼 가져오게되면, @mui/icons-material에서 내보내고있는 모든 모듈이 번들 사이즈에 포함된다.

필요한 모듈만 사용하기 위해 `@mui/icons-material` 와 `@mui-material` 라이브러리를 default export로 정의된 경로만 import하는 방식으로 변경해 주고 다시 Treemap 확인!

> 아래 이미지는 @mui/icons-material 만 진행한 이미지이다.
> @mui-material 번들 사이즈는 다음 이미지를 확인

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g367731lpp5ipas37as9.png)

**결과**
> @mui/icons-material: `6.1MiB` -> `1.8KiB`
> @mui-material: `1.5MiB` -> `711.3KiB`

&nbsp;

## 라이브러리 경량화2 (Firebase)

Treemap을 보면서 다음으로 큰 비중을 차지하고 있는 Firebase가 보였다.

검색을 통해 찾은 결과 많은 firebase SDK를 사용하고 있다면 다음과 같은 방법으로 SDK를 경량화 할 수 있다고 한다.

해당 솔루션이 바로 [Firestore Lite](https://firebase.google.com/docs/firestore/solutions/firestore-lite?hl=ko) 이다.

그리고 다음과 같이 모든 파일에 존재하는 경로를 변경해 주었다.

```typescript
// as-is
import { getFirestore } from 'firebase/firestore';

// to-be
import { getFirestore } from 'firebase/firestore/lite';
```

그리고 Treemap 확인!

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lx70ibdbj08l4e2dld3b.png)

**결과**

> firebase/firestore: `519.6KiB` -> `172.0KiB`

주의할 점으로 지원되지 않는 API 기능들도 있으니 확인하고 적용하면 되겠다.

또한 Firestore Lite는 실시간 업데이트와 연결이 필요 없는 앱에 적합하다고 한다.

그리고 나서 프로젝트 빌드 실행!

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/htz1ihrbf8zt2ys1zp2u.png)

**빌드 결과**
> 빌드 크기: `1,074KB` -> `803.93KB`
> 빌드 시간: `1m 46s` -> `6.20s`

이 정도면 어느 정도는 빌드 최적화를 수행한 것 같지만 아직 한 가지 더 할 것이 남아있다.

&nbsp;

## 빌드 경량화

파일을 빌드하면 다음과 같은 경고 문구가 뜬다

```text
- Using dynamic import() to code-split the application
- Use build.rollupOptions.output.manualChunks to improve chunking: https://rollupjs.org/configuration-options/#output-manualchunks
- Adjust chunk size limit for this warning via build.chunkSizeWarningLimit.
```

`Using dynamic import() to code-split the application` 방법은 이미 적용 되었으니 다음 방법으로 시도해 보려고 한다.

내용을 번역해 보면, 청크 개선을 위해`build.rollupOptions.output.manualChunks` 사용하라고 한다. 그 방법은 [여기](https://rollupjs.org/configuration-options/#output-manualchunks) 에 있다고 한다.

즉, 청크 파일을 Code Split 하여 빌드 크기를 줄일 수 있다는 의미로 해석된다. 그래서 청크파일 중 크기가 가장 큰 파일을 분할해 주었다.

```javascript
// vite.config.js
build: {
  rollupOptions: {
    output:{
      manualChunks(id) {
        if (id.includes('node_modules')) {
          return id.toString().split('node_modules/')[1].split('/')[0].toString();
        }
      }
    }
  }
}
```

블록을 분해하여 큰 블록을 더 작은 블록으로 나누는 방법이라고 한다. 이렇게 전부 코드를 분할하는 방식 보다는 다음과 같은 방식으로 변경해 주었다.

```javascript
// vite.config.js
build: {
  rollupOptions: {
     output: {
       manualChunks: {
         firebase: [
           'firebase/app',
           'firebase/auth',
           'firebase/storage',
           'firebase/firestore',
          ],
          react: [
            'react-dom',
            'react-query',
            'react-router-dom'
          ],
        }
     },
  },
},
```

큰 사이즈의 라이브러리들만 골라 선언해 주었다.

큰 사이즈의 라이브러리는 사용자가 처음 페이지를 방문할 때 필요 없는 자원들을 모두 불러오기 때문에 초기 로딩 속도를 지연시킬 수 있기 때문에 큰 사이즈 라이브러리를 대상으로 코드 분할해 주었다.

그리고 빌드 후 확인!

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ztkl4iizscpsa5f6kzta.png)

**빌드 결과**
> 빌드 크기: `803.93KB` -> `289KB`
> 빌드 시간: `6.20s` -> `5.57s`

&nbsp;

## 마무리

최종적으로 빌드 시간이 단축되고 크기도 줄어서 사용자에게 최적화된 렌더링 경험을 줄 수 있게 되었다.

이 모든 작업을 요약하면 `Tree Shaking`과 `Code Split` 만으로도 좋은 최적화 결과를 얻을 수 있다는 사실을 알게 되었다.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iazww65h53cw8lqykuo0.png)