[React] 코드 스플리팅을 적용했을 뿐인데, 초기 로딩이 줄어들었습니다

2025. 12. 27. 22:28·💻 개발/🦕 React
728x90
반응형

 

| 인트로

안녕하세요, 팡일입니다.

 

이전 포스팅에서는 프로젝트에서 이미지 로딩 구조를 개선하며 성능을 정량적으로 측정하고 검증한 과정을 정리해보았습니다.

 

이번에는 그 연장선상에서, 초기 로딩 성능에 직접적인 영향을 주는 코드 스플리팅(Code Splitting)을 실제 프로젝트에 적용하고, “번들 크기가 줄어들면, 사용자는 무엇을 체감하게 되는가?”를 직접 확인해본 과정을 공유해보려고 합니다.

 

단순히 “코드 스플리팅을 적용했다”가 아니라, 왜 필요했는지 → 어떻게 적용했는지 → 실제로 무엇이 달라졌는지 를 중심으로 정리해보았습니다.

 

 

 

| 왜 개선하게 되었는지

기존 프로젝트는 React Router 기반의 SPA 구조로, 다음과 같은 특징을 가지고 있었습니다.

  • Home, About, Worship, Contact, Schedule 페이지가 존재
  • 첫 페이지 진입 시 모든 페이지 컴포넌트가 한 번에 로딩
  • 사용자가 방문하지 않을 페이지 코드도 초기 번들에 포함

-> 즉, 구조적으로는 SPA의 장점을 가지고 있었지만, 번들 관점에서는 MPA에 가까운 비효율적인 로딩 구조였습니다.

 

이 방식의 문제점은 명확했습니다.

  • 초기 로딩 시 JS 번들 크기 증가
  • JS 파싱 및 실행 비용 증가
  • 네트워크 및 CPU 리소스 낭비
  • 페이지 수가 늘어날수록 성능 저하가 누적되는 구조

-> 특히 “초기 로딩에 꼭 필요하지 않은 코드까지 모두 내려받고 있다”는 점이 가장 큰 개선 포인트였습니다.

 

 

 

 

| 어떻게 개선하게 되었는지

이번 개선의 핵심은 라우트 단위 코드 스플리팅입니다. 이를 위해 React에서 제공하는 세 가지 개념을 활용했습니다.

 

1) 코드 스플리팅(Code Splitting)

: 코드 스플리팅이란, 애플리케이션 전체 코드를 하나의 번들로 묶지 않고, 필요한 시점에 필요한 코드만 로딩하도록 분리하는 기법입니다.

 

SPA에서 특히 중요한 이유는, “한 페이지 앱이지만, 실제로는 여러 페이지처럼 동작하기 때문”입니다.

 

 

 

2) lazy 로딩 (React.lazy)

: React.lazy는 컴포넌트를 동적으로 import하여, 해당 컴포넌트가 실제로 렌더링되는 시점에 JS 파일을 로딩하도록 도와줍니다.

const WorshipPage = lazy(() => import("../Pages/WorshipPage/WorshipPage"));

 

이렇게 하면 Worship 페이지의 JS는 /worship 경로로 이동할 때만 다운로드됩니다.

 

 

 

3) Suspense

: Suspense는 lazy 로딩 중인 컴포넌트가 아직 준비되지 않았을 때 사용자에게 보여줄 fallback UI를 정의하는 역할을 합니다.

다만, 이번 개선에서는 Suspense를 MyRoutes가 아닌 Layout 내부의 Outlet 영역에 배치했습니다.

즉, 전체 라우트 구조를 감싸는 방식이 아니라, 실제로 페이지 콘텐츠가 렌더링되는 영역만 비동기로 처리하도록 구조를 조정했습니다.

<ContainerOutler>
  <Suspense fallback={<PageSkeleton />}>
    <Outlet />
  </Suspense>
</ContainerOutler>

 

 

이 구조의 핵심은 다음과 같습니다.

  • Header / Footer는 즉시 렌더링
  • 페이지 본문(Outlet)만 lazy 로딩
  • 로딩 중에도 전체 레이아웃은 유지

 

"왜 Suspense를 Outlet에 두었는가?"에 대해서 공유해보면, 초기에는 MyRoutes 레벨에서 Suspense를 사용했지만, 이 방식에는 한 가지 UX 문제가 있었습니다. 페이지 이동 시 Header / Footer까지 함께 사라지고 fallback UI가 전체 화면을 덮는 현상이 발생했습니다.

 

이는 사용자 입장에서 “페이지가 전환되는 중인지, 앱이 멈춘 것인지” 구분하기 어려운 경험을 만들 수 있었습니다. 그래서 Suspense의 범위를 의도적으로 좁혔습니다.

 

 

| 적용 결과 (구조적 변화)

  • 기존:
    • 모든 페이지 컴포넌트 → main.js에 포함
    • 페이지 전환 시에도 전체 구조가 다시 로딩되는 느낌
  • 개선 후:
    • main.js → 공통 Layout(Header, Footer) + Router
    • 각 페이지 → 개별 JS chunk
    • Suspense는 Outlet 영역에만 적용

 

 

 

| 정량적 지표 확인 방법 및 실제 결과

1) 측정 기준

: 코드 스플리팅 적용 전·후의 변화를 감각이 아닌 수치로 검증하기 위해, 다음과 같은 기준으로 성능 변화를 측정했습니다.

  • 측정 도구
    • source-map-explorer
    • Chrome DevTools (Network, Performance 참고)
  • 측정 대상
    • Production build 결과 (npm run build)
    • Netlify에 실제 배포된 환경
  • 비교 기준
    • gzip 기준 JS 번들 크기
    • 초기 로딩 시점에 반드시 다운로드되는 main.js
    • 코드 스플리팅 이후 생성된 페이지 단위 JS chunk 구조

특히 이번 측정에서는 “초기 진입 시 사용자에게 강제로 부과되는 비용이 얼마나 줄었는가” 에 초점을 맞추었습니다.

 

 

2) 개선 전 → 개선 후 결과

: 코드 스플리팅 적용 후, production build 결과에서 다음과 같은 변화를 확인할 수 있었습니다.

File sizes after gzip:

66.08 kB (-5.2 kB)  build/static/js/main.[hash].js

 

이를 정리하면 다음과 같습니다.

항목 개선 전 개선 후 변화
main JS 번들 크기 (gzip) 약 71.28 kB 66.08 kB -5.2 kB
감소율 - - 약 7.3% 감소

 

 

3) 수치가 가지는 의미

: 5.2kB라는 숫자만 보면 작아 보일 수 있습니다. 하지만 이 수치는 단순한 파일 크기 감소가 아니라, 초기 로딩 시 반드시 다운로드되는 JS와 페이지 수와 무관하게 항상 파싱·실행되던 코드 가 줄어들었다는 점에서 의미가 큽니다.

 

즉, 초기 진입 시 네트워크 다운로드 비용 감소, JS 파싱 및 실행 비용 감소, DOMContentLoaded 시점 단축으로 이어지는 구조적 개선

이 함께 발생한 것입니다.

 

실제로 Netlify 배포 환경에서 확인한 결과, DOMContentLoaded 시점 역시 약 40~60% 수준으로 단축되는 경향을 보였고, 초기 화면이 준비되는 체감 속도 또한 명확하게 개선되었습니다.

 

 

4) 구조적 관점에서의 정량 개선

: 코드 스플리팅 적용 전에는 모든 페이지 코드가 하나의 main 번들에 포함되어 있었지만, 적용 이후에는 다음과 같은 구조로 변경되었습니다.

  • main.[hash].js
    → 공통 Layout, Router, 필수 로직만 포함
  • xxx.[hash].chunk.js
    → 각 페이지별로 분리된 JS

그 결과, 아래와 같이 점진적 로딩 구조를 갖게 되었습니다.

  • 초기 진입 시: main bundle만 로딩
  • 페이지 이동 시: 해당 페이지의 JS chunk만 추가 로딩

 

즉, 이번 개선은 단순히 파일 크기를 줄인 것이 아니라,  “초기 진입 시 반드시 지불해야 하는 비용” 자체를 줄인 구조적 개선이라고 볼 수 있습니다.

 

 

 

| 마무리

이번 코드 스플리팅 개선을 통해 느낀 점은 명확했습니다.

  • 성능 개선은 “느낌”이 아니라 측정과 구조의 문제
  • 단순히 기능 구현에서 끝나는 것이 아니라
    • 왜 비효율적인지
    • 어디를 나눠야 하는지
    • 정말 효과가 있었는지
    • 를 끝까지 확인해야 의미가 있다는 점입니다.

 

특히 이번 작업을 통해 느낀 점은, 코드 스플리팅은 단순히 번들을 나누는 기술이 아니라, “어디를 비동기로 만들 것인가”에 대한 UX 설계라는 점이었습니다. Suspense의 위치 하나만 바꿔도 사용자가 느끼는 앱의 안정감은 크게 달라질 수 있다는 것을 직접 체감할 수 있었습니다.

 

728x90
반응형

'💻 개발 > 🦕 React' 카테고리의 다른 글

[React] TanStack Query(React Query) 활용하기 - useMutation으로 데이터 생성·수정·삭제 마스터하기  (0) 2026.01.15
[React] TanStack Query(React Query) 깊게 파고들기 : useQuery와 캐시 생명주기의 모든 것  (0) 2026.01.15
[React] public 이미지에서 import 구조로 (이미지 최적화 개선기)  (1) 2025.12.27
[React] target="_blank" ESLint 경고의 의미와 해결 방법 (react/jsx-no-target-blank)  (0) 2025.12.27
[React] React에서 한글 입력(IME) 깨짐 문제 해결하기  (1) 2025.08.28
'💻 개발/🦕 React' 카테고리의 다른 글
  • [React] TanStack Query(React Query) 활용하기 - useMutation으로 데이터 생성·수정·삭제 마스터하기
  • [React] TanStack Query(React Query) 깊게 파고들기 : useQuery와 캐시 생명주기의 모든 것
  • [React] public 이미지에서 import 구조로 (이미지 최적화 개선기)
  • [React] target="_blank" ESLint 경고의 의미와 해결 방법 (react/jsx-no-target-blank)
pangil_kim
pangil_kim
기록을 통해 지속적인 성장을 추구합니다.
  • pangil_kim
    멈추지 않는 기록
    pangil_kim
  • 전체
    오늘
    어제
  • 📝 글쓰기
      ⚙️ 관리

    • 분류 전체보기 (405) N
      • 💻 개발 (176) N
        • ※ 참고 지식 (9)
        • 🦕 React (13)
        • 🎩 Next.js (25)
        • 📘 TypeScript (4)
        • 📒 JavaScript (8)
        • 🟩 Node.js (7)
        • 📀 MySQL (24)
        • 🌸 Spring Boot (5)
        • 👷 SveleteKit (24)
        • 🩵 Flutter (11)
        • 🌀 Dart (2)
        • 🌈 CSS (5)
        • 🔸Git (1)
        • 🔥 Firebase (4)
        • 🧑🏻‍💻 코테 (29) N
        • 🕸️ 알고리즘 (4)
        • 🌤️ AWS (1) N
      • 📋 프로젝트 (4) N
        • ☄️ 트러블 슈팅 (2) N
        • 🧑🏻‍💻 서비스 소개 (2)
      • ✍🏻 회고 (52) N
        • ☀️ 취준일지 (6) N
        • 🍀 우테코 (32)
        • 👋 주간회고 (1) N
      • 📰 정보 공유 (12)
      • 🧑🏻‍💻 개발자라면? (1)
      • 🏫 한동대학교 (153)
        • Database (15)
        • Software Engineering (18)
        • EAP (22)
        • 일반화학 (26)
        • 25-1 수업 정리 (19)
        • Computer Networking (36)
        • OPIc (2)
        • 미술의 이해 (15)
  • 최근 글

  • 인기 글

  • 태그

    웹 프론트엔드 8기
    데이터베이스
    설교
    FE
    QT
    우아한테크코스
    예배
    computer networks and the internet
    어노인팅
    컴네
    네트워킹
    typeScript
    우테코
    프론트엔드
    날마다 솟는 샘물
    CCM
    주일
    GLS
    전산전자공학부
    우테코 8기
    묵상
    날솟샘
    csee
    웹개발
    한동대학교
    부트캠프
    프리코스
    글로벌리더십학부
    찬양
    고윤민교수님
  • 최근 댓글

  • 250x250
  • hELLO· Designed By정상우.v4.10.4
pangil_kim
[React] 코드 스플리팅을 적용했을 뿐인데, 초기 로딩이 줄어들었습니다
상단으로

티스토리툴바