[React] 무지성 코드 스플리팅의 폐혜

한호수 (The Lake)·2023년 4월 30일
4
post-thumbnail
post-custom-banner

코드 스플리팅은 무엇일까?

자바스크립트로 개발 시 번들러를 통해서 자바스크립트 모듈들을 모아서 한가지 번들 파일로 만들어 배포하게 된다. 이때 모든 자바스크립트 파일을 모아서 만든 번들 파일은 프로젝트 규모에 따라 커지게 되며 초기 로딩 시 당장 필요 없는 코드까지 모아서 받기 때문에 렌더링이 늦어지는 단점이 있다.

이를 해결하기 위해서 번들러에서 자바스크립트를 작은 단위(chunk)로 쪼개서 필요할때 불러오는 방식인 코드 스플리팅을 지원한다.

예) Home 페이지 접속 시 main 번들과 Home 컴포넌트에 대한 js 파일만 다운 받고 나중에 필요하다면 게시글 컴포넌트나, 포스트 컴포넌트들에 관한 js파일을 받을 수 있다.

실제로 성능 변화가 있었나?

사실 코드 스플리팅은 이전부터 프로젝트마다 적용하고 있었는데 실제 성능변화에 관해서 의구심이 생겨서 비교해보게 되었다.

리액트 프로젝트에서는 컴포넌트를 동적으로 불러오기 위해서는 lazy 를 사용해서 import해야 했었고, 이를 이용해서 Router.tsx 부분에서 모든 페이지 컴포넌트들을 lazy를 이용해서 불러왔었다.

import { lazy, Suspense } from "react";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Loader from "../components/Loader";


const Login = lazy(() => import("../pages/Login/Login"));
const LoginEmail = lazy(() => import("../pages/LoginEmail/LoginEmail"));
const SplashScreen = lazy(() => import("../pages/SplashScreen/SplashScreen"));
const Feed = lazy(() => import("../pages/Home/Feed"));

// ...중략

function Router() {
  return (
    <BrowserRouter>
      <GlobalModal />
      <Suspense fallback={<Loader />}>
        <Routes>
          <Route path="/" element={<SplashScreen />} />
          <Route path="/login" element={<Login />} />
          <Route path="/login/loginEmail" element={<LoginEmail />} />
          <Route path="/feed" element={<Feed />} />
          
		  // ...중략
          
        </Routes>
      </Suspense>
    </BrowserRouter>
  );
}

export default Router;

스플리팅이 되는지 안되는지 여부는 크롬 개발자 도구(F12)의 네트워크 탭에서 JS탭을 선택하여 새로고침 후 볼 수 있다.
(새로고침 시 Ctrl + F5 또는 개발자 도구를 열고 새로고침 아이콘에 마우스 오른쪽을 클릭해서 강력 새로고침으로 캐시를 사용하지 않아야한다.)

코드 스플리팅 적용

bundle.js 의 크기가 534kB로 불러오는데 60ms가 걸렸다. 하지만 bundle.js에서 분리된 GlobalModal, TabMenu, HomePost, HomeFeed 마다 각각 4ms, 4ms, 6ms, 9ms 즉 23ms가 더걸리게 되면서 결론적으로 83ms가 걸리게 되었다.

코드 스플리팅 미적용

bundle.js 의 크기가 772kB로 불러오는데 83밀리초가 걸렸다.

bundle.js가 772kB에서 534kB로 238kB가 줄었지만 시간은 83ms로 동일하게 걸렸다. (매번 시도할때마다 시간이 다르지만 비슷한 시간이 걸렸다) 이는 방금 분할하여 다운받은 4개의 컴포넌트의 크기를 감안하더라도 전혀 성능 향상이라고 볼 수 없고 오히려 페이지 이동 시 추가적으로 다운받을 코드들을 생각하면 오히려 성능 저하라고 보는게 맞다.

심지어 테스트 환경같은 경우 localhost에서 진행했기 때문에 통신간에 소모되는 시간이 없다고 봐도 무방할 정도이고 실제 배포된 환경에서는 서버간의 요청시간이 있기 때문에 훨씬 더 큰 성능저하를 불러왔다.

아무리 작은 파일이더라도 서버로 리소스 요청 시 소모되는 시간 때문에 추가적인 시간이 소모되었다.

이런 문제가 발생한 이유는 초기 로딩 시 같이 받아와야할 코드들까지 분할해서 여러번의 요청을 했기 때문이고, 작은 단위의 컴포넌트까지 분할해서 가져오기 때문이다. 그렇기 때문에 처음 로드 시 번들에 들어갈 컴포넌트인지 생각해보고, 분할해야할 사이즈인지 생각해보는게 제일 중요할것이다.

결론

코드 스플리팅은 자바스크립트 번들의 크기가 커서 컴포넌트 단위로 분할이 필요하고 당장 필요한 컴포넌트만 불러온다면 로딩시간이 단축되어 성능상 이점을 얻을 수 있을것이다.

초기 로드 시 불필요하게 코드 스플리팅한 컴포넌트들을 다시 번들링해서 성능 향상시켰음

하지만 정말 분할이 필요한 경우가 아니라면 여러번의 요청을 줄이기 위해 번들링하는 목적이 사라지게 되고, 오히려 성능저하를 가져온다는것을 깨달았다.

그리고 분할한다고 해도 지금 사용하지 않아 필요할때만 불러와야하는 큰 컴포넌트들에게만 선택적으로 분할하는게 가장 좋은 선택이라는걸 배웠다.

Reference

번들러의 역사
https://yozm.wishket.com/magazine/detail/1261/

profile
항상 근거를 찾는 사람이 되자
post-custom-banner

0개의 댓글