tree shaking

nearworld·2023년 8월 11일
0

리액트 기초

목록 보기
11/12
post-custom-banner

Tree shaking?

Tree shaking은 번들링 과정에서 Dead Code를 제거하는 행위를 말합니다.
Dead Code 는 아래와 같이 사용하지 않는 코드를 의미합니다.

Tree shaking 번들링 과정에서 발생하는 행위라고 했습니다.
번들링은 번들러에 의해서 수행됩니다.
그럼 이 Tree shaking을 확인하려면 번들러를 사용해야한다는 것을 의미합니다.

번들러?

번들러는 영어로 Bundler 단어입니다.
구글에서 검색해보면 아래와 같은 이미지들이 나옵니다.

물건 여러개가 묶여있는 것이 보입니다.
번들이 의미하는 것은 물체들을 한 묶음으로 만들어내는 것입니다.
그리고 이러한 행위를 하는 것을 번들러라고 합니다.

번들러의 종류는 여러가지가 있습니다.
Webpack, Rollup 등..

번들링을 지원하는 프론트엔드 프레임워크가 여러개 있겠지만 저는 리액트를 사용합니다.
그래서 리액트를 예시를 들겠습니다.

CRA로 프로젝트를 생성하고 node_modules 폴더를 확인합니다.
위 이미지처럼 react-scripts라는 폴더를 확인할 수 있습니다.
webpackreact-scripts/config 디렉토리에 들어있음을 알 수 있습니다.

이제 CRA로 생성된 리액트 프로젝트는 Webpack을 통해 번들링 과정을 수행하도록 세팅되어있다는 것을 확인했으니 코드를 들여다보며 tree shaking에 대해 알아보겠습니다.

먼저 react-router-dom 라이브러리를 이용하여 앱의 라우터를 설계해놓은 router.jsx 파일을 들여다보겠습니다.

// router.jsx
import Home from './Home.jsx';
import Signin from './Signin.jsx';

export const router = createBrowserRouter([
  {
    path: '',
    element: <Home />
  },
  {
    path: '/signin',
    // element: <Signin />
  }
]);

router.jsx 파일은 아래 App.jsx에서 import 됩니다.

// App.jsx
import { RouterProvider } from 'react-router-dom';
// 아래 router 변수가 import 되었습니다.
import { router } from './router.jsx';

function App() {
  return <RouterProvider router={router} />
}

이 import된 파일들은 번들링 과정을 거치면서 하나의 js 파일로 최종 변환될때 그 파일 안에 들어가게 됩니다. (즉, 지금 당장 특정 코드가 실행될 필요가 없더라도 실행되게 된다는 얘기입니다.)

이 말은 지금 당장 불필요한 연산을 수행함으로써 App이 CPU의 자원을 불필요하게 많이 점유한다는 것에 있습니다. (최적화가 안되어 있음을 의미합니다)

제가 이해한 번들링 과정을 위 App.jsx 코드를 토대로 순서대로 보면 이렇습니다.

  1. 번들링 시작
  2. index.jsx 실행
  3. index.jsx 에서 import되고 있는 App.jsx 실행
  4. App.jsx 에서 import되고 있는 router.jsx 실행
  5. router.jsx 안에서 import 되고 있는 모든 파일들을 실행
  6. 각종 컴포넌트 안에서 import 되고 있는 모든 파일들을 실행

이 번들링 과정을 이해할 때 중요한 요소가 ES6 modules 시스템의 작동 방식이라는 것을 배웠습니다.
그 이유는 A 라는 모듈을 여러 다른 모듈에서 import해봤자 이 A 모듈은 한 번만 평가되기 때문입니다.
이렇게 여러번 import해도 오로지 하나의 인스턴스만 존재하는 것을 싱글톤 Sigleton이라고 하는 것도 배웠습니다.

싱글톤 (Singleton)
하나의 클래스에 오직 하나의 인스턴스만 생성하는 것을 의미

ES6의 import 작동 방식을 이해하지 못하면 아래의 config 모듈이 다른 모듈에 의해 여러번 import 되는 상황에서 잘못 이해할 수도 있습니다.

아래에 axios의 create 메서드가 호출되고 있습니다.
그리고 메서드 실행결과인 리턴 값은 axiosInstance에 담깁니다.
이때 axiosInstnace 변수를 여러 모듈에서 여러번 import해도 첫 import됐을 때만 실행되고 나머지 import문에서는 첫 실행 결과값을 가져다 쓰기때문에 localStorage.getItem이 액세스 토큰을 첫 import 시점에서만 읽어들인다는 것을 알 수 있습니다.

결국, 아래의 코드는 액세스 토큰을 한 번만 읽어들이기 때문에 올바른 axios 작성법이 아님을 알 수 있습니다. 그리고 이것은 ES6 모듈 시스템 작동방식에서 모듈은 싱글톤(Singleton)임을 이해하는게 리액트 프로젝트를 개발할 때 중요하다는 것을 의미한다고 생각합니다.

// config.ts
export const axiosInstance = axios.create({
  baseURL: 'https://example.com',
  headers: {
    'Authorization': `Bearer ${localStorage.getItem('access_token')}`
  }
});
profile
깃허브: https://github.com/nearworld
post-custom-banner

2개의 댓글

comment-user-thumbnail
2023년 8월 11일

안녕하세요.
현재 벨로그에 이미지를 입력하면 업로드 실패가 뜨는데 혹시 별도로 올리시는 방법이 있으실까요??

1개의 답글