본문 바로가기

개발자 강화/프론트엔드

🌟[공부] React의 트리 쉐이킹이란?

React의 트리 쉐이킹(Tree Shaking)?

  • 자바스크립트에서 사용하지 않는 코드를 제거해 번들 크기를 줄이는 최적화 기법
  • ES6의 모듈 시스템(ESM)에서의 정적 분석(Static Analysis)을 기반으로 이루어짐

* 정적 분석(Static Analysis)

- 프로그램을 실행하지 않고, 코드 자체의 문법 구조(Syntax Tree)를 분석함.

- 프로그램 구조, 흐름, 의존성 이해하고 최적화 또는 오류 탐지 수행함.

- 어떤 모듈이 다른 모듈에 의존하는지, 어떤 함수나 변수가 실제로 사용되는지 추적함.

- ES6 모듈의 import/export 키워드는 정적으로 정의되어, 분석기가 전체 코드를 미리 파악할 수 있음.

 

*정적으로 정의

- 코드가 런타임에 결정되지 않고, 컴파일 시점이나 분석 시점에 구조와 동작이 명확히 결정됨


 

트리 쉐이킹의 주요 개념

  • 불필요한 코드 제거
    • 프로젝트에서 특정 모듈을 import 했지만 사용하지 않는 경우, 트리 쉐이킹으로 최종 번들에서 코드를 제거함
    • React는 불필요하게 import된 컴포넌트, 유틸 함수 등을 트리 쉐이킹으로 제거할 수 있음
  • ES6 모듈 시스템
    • 트리 쉐이킹은 import/export 키워드로 작성된 정적 모듈에서 동작함
    • require를 사용하는 CommonJS 모듈은 트리 쉐이킹이 불가능함
  • 번들러와 연계
    • Webpack, Rollup, Parcel 등의 번들러는 트리 쉐이킹 기능을 지원함.
    • Webpack에 mode: "production" 설정하면 자동으로 트리 쉐이킹 수행

 

React에서 트리 쉐이킹 적용되는 방식

  • React 컴포넌트: 특정 컴포넌트를 import 했지만, 사용하지 않는 경우에 번들에서 제거됨
// example.js
export const A = () => <div>A</div>;
export const B = () => <div>B</div>;

// App.js
import { A } from "./example"; // B는 사용되지 않으므로 제거됨.
  • React 유틸리티 함수나 라이브러리: 특정 기능이나 외부 라이브러리에서 사용하지 않는 함수가 제거됨
import { useState, useEffect } from "react";
// useEffect가 사용되지 않으면 번들에서 제거됨.
  • 라이브러리에서 최적화(lodash-es, date-fns): 필요한 함수만 import하면 트리 쉐이킹이 가능해 번들 크기 줄일 수 있음
import { debounce } from "lodash-es"; // lodash-es는 트리 쉐이킹에 최적화됨.

 

React 트리 쉐이킹 팁

  • ES6 모듈 사용: React와 관련된 모든 코드에서 import/export 사용
  • Named Import 사용
// 좋음 (Named Export)
export const A = () => {};
export const B = () => {};

// 나쁨 (Default Export)
export default { A, B }; // 트리 쉐이킹 비효율적.
  • 라이브러리 최적화: 트리 쉐이킹을 지원하는 라이브러리인 lodash-es, date-fns 사용함
  • Production Mode 사용: Webpack에서 (mode:"production")을 설정해 트리쉐이킹과 Dead Code Elimination 활성화함

 

React 트리 쉐이킹 한계와 주의점

  • Dynamic Import: 동적 import() 구문은 트리 쉐이킹에 영향을 받을 수 없음
    • 특정 이벤트 발생 시, 모듈을 동적으로 로드하는 방식으로 코드를 작성하는 경우
import React, { Suspense } from 'react';

// 동적으로 컴포넌트를 로드
const LazyComponent = React.lazy(() => import('./MyComponent'));

function App() {
  return (
    <div>
      <h1>My App</h1>
      <Suspense fallback={<div>Loading...</div>}>
        <LazyComponent /> {/* 컴포넌트가 동적으로 로드됨 */}
      </Suspense>
    </div>
  );
}

export default App;
  • Side Effect: 모듈이 Side Effect를 포함하고 있다면 해당 코드가 번들에서 제거되지 않을 수 있음.
    • package.json에서 sideEffects:"false"를 설정해서 방지할 수 있음.

 

이 블로그에 이와 관련된 글

CommonJS와 ES Module(ESM) 차이점이란? (FE.250103) https://developer-dreamer.tistory.com/142