[Day 4] 왜 번들링이 필요한가? (Webpack, Vite, Tree Shaking까지)

짱효·2026년 4월 24일

프론트엔드 기초 다시 쌓기 챌린지 4일차.
Day 2에서 "빌드하면 파일이 합쳐진다"는 걸 배웠다면,
오늘은 "왜 합쳐야 하는지", "누가 합쳐주는지", "안 쓰는 코드는 어떻게 되는지" 를 깊이 파헤쳤다.
그리고 "네트워크가 뭐야?", "번들 사이즈가 크면 뭐가 느려지는 거야?" 라는 궁금증까지 해결했다.


📦 번들링이 필요한 이유

번들링 없이 배포하면 생기는 일

프로젝트에 파일이 보통 100~500개 있다.
이걸 그대로 배포하면?

사용자가 홈페이지 접속
→ 브라우저: "HTML 주세요"         (1번 요청)
→ 브라우저: "Header.tsx 주세요"    (2번 요청)
→ 브라우저: "Footer.tsx 주세요"    (3번 요청)
→ 브라우저: "api.ts 주세요"        (4번 요청)
→ ...
→ 총 50개 요청 😱

요청 하나하나에 네트워크 연결, 파일 전송, 파싱이 필요하다.
파일 자체가 가벼워도 요청 횟수 때문에 느려진다.

번들링하면?

17개 파일 → 3개로 합침

main.js      ← 핵심 코드 전부
vendor.js    ← 라이브러리 (react, next 등)
styles.css   ← CSS 전부

→ 총 4개 요청 ⚡ (50번 → 4번)

비유: 이사할 때 물건을 하나씩 옮기면 200트립,
박스에 묶어서 옮기면 3트립. 번들링은 "박스에 묶는 것" 이다.


🔧 번들러: 번들링을 해주는 도구

Webpack (웹팩)

등장: 2012년 (가장 오래됨)
비유: 만능 이사 업체 — 뭐든 다 해줌, 근데 좀 느림
  • 가장 많이 쓰임 (아직도 대부분 회사에서 사용)
  • 설정이 복잡함
  • 플러그인 수천 개 → 뭐든 가능
  • Next.js가 내부적으로 Webpack 사용 중

Vite (비트)

등장: 2020년
비유: 퀵서비스 배달 — 엄청 빠름, 가볍고 심플
  • 개발 서버 속도가 미친 듯이 빠름
  • Webpack은 전체 파일을 다 번들링한 후 서버 시작
  • Vite는 필요한 파일만 그때그때 처리 → 즉시 시작
개발 서버 시작 속도 (파일 100개 기준)
Webpack: 10초
Vite:    0.5초

esbuild (이에스빌드)

등장: 2020년
비유: 로켓 배달 — 미친 속도, 단순한 일만 잘함
  • Go 언어로 만듦 → JS 도구보다 10~100배 빠름
  • 단독보다 Vite 안에서 엔진으로 쓰임

한눈에 비교

구분WebpackViteesbuild
속도느림빠름미친듯이 빠름
설정복잡간단매우 간단
생태계거대함커지는 중작음
비유만능 이사 업체퀵서비스 배달로켓 배달

실무 기준:

  • Next.js 쓰면 → Webpack (자동 설정이라 직접 건드릴 일 거의 없음)
  • 새 프로젝트 시작한다면 → Vite 추천

🌳 Tree Shaking: 안 쓰는 코드 자동 삭제

비유

나무를 흔들면 죽은 잎이 떨어진다.
코드를 빌드할 때 안 쓰는 코드가 자동으로 삭제되는 것.

실제 예시

// lodash에는 함수가 300개 있음
// 내가 쓰는 건 딱 2개

import { debounce, throttle } from 'lodash'

Tree Shaking 없으면: 함수 300개 전부 포함 → 70 KB
Tree Shaking 있으면: 2개만 포함 → 3 KB

67 KB 절약! 사용자가 안 쓰는 코드를 안 받아도 된다.

⚠️ Tree Shaking이 안 되는 패턴

// ❌ 이렇게 쓰면 Tree Shaking 안 됨
import _ from 'lodash'
_.debounce(...)
// → "lodash 전체를 가져와" 라는 뜻
// → 번들러: "뭘 쓸지 모르니까 다 넣어야지"

// ✅ 이렇게 써야 Tree Shaking 됨
import { debounce } from 'lodash'
debounce(...)
// → "debounce만 가져와" 라는 뜻
// → 번들러: "debounce만 넣으면 되네!"

이게 named import vs default import의 차이.
앞으로 라이브러리 import 할 때 항상 의식하자.


📏 번들 사이즈 확인하는 법

방법 1: yarn build 로그

$ yarn build

Route (pages)                    Size     First Load JS
─────────────────────────────────────────────────────────
○ /                              5.2 kB        87.3 kB
○ /about                         2.1 kB        84.2 kB
+ First Load JS shared by all   82.1 kB
용어의미
Size그 페이지에서만 쓰는 JS 크기
First Load JS그 페이지 처음 열 때 받는 총 JS

건강한 번들 사이즈 기준

✅ First Load JS < 100 KB   → 좋음
⚠️ First Load JS 100-200 KB → 개선 필요
❌ First Load JS > 200 KB    → 문제 있음

방법 2: @next/bundle-analyzer

번들 사이즈를 눈으로 볼 수 있는 도구.
큰 네모 박스일수록 용량이 큰 파일이다.
비정상적으로 큰 박스를 찾으면 최적화 대상.


🚨 실전에서 자주 나는 번들 사이즈 문제

문제 1: moment.js

moment.js → 전체 크기 약 300 KB 😱
전세계 언어팩이 다 포함돼서 엄청 무거움

해결: day.js (2 KB) 또는 date-fns로 교체

문제 2: lodash 전체 import

// ❌ 70 KB 전부 불러옴
import _ from 'lodash'

// ✅ 필요한 것만 (3 KB)
import { debounce } from 'lodash-es'

문제 3: 아이콘 라이브러리 전체 import

// ❌ 아이콘 수천 개 전부 불러옴
import * as Icons from 'react-icons'

// ✅ 필요한 것만
import { FiSearch, FiHeart } from 'react-icons/fi'

🌐 "네트워크"가 정확히 뭐야?

Day 3에서 Network 탭을 배우면서 궁금한 점이 생겼다.
"네트워크가 브라우저가 동작하는 과정인가?"

정답

네트워크 = 컴퓨터끼리 데이터를 주고받는 통로

브라우저 동작 과정 자체가 아니라, "데이터가 이동하는 도로" 같은 개념이다.

당신 (브라우저)  ←──전화선──→  친구 (서버)
                    ↑
                이게 네트워크!
  • 브라우저 = 파일을 요청하는 쪽
  • 서버 = 파일을 보내주는 쪽
  • 네트워크 = 그 사이의 통로

브라우저 전체 동작에서 네트워크의 위치

1. 사용자가 URL 입력
2. 🌐 네트워크: 서버한테 파일 요청 → 파일 받음    ← Network 탭
3. 🎨 렌더링: 받은 파일로 화면 그림               ← Performance 탭
4. ⚙️ JS 실행: 기능 동작                        ← Console 탭
5. 📡 추가 요청: API 호출 등                     ← Network 탭

네트워크는 2번과 5번 단계. 전체 과정 중 "파일을 주고받는 부분" 만 담당한다.


📦 번들 사이즈가 크면 정확히 뭐가 느려지는가?

"빌드 속도가 느려지는 건가? 사용자 로딩이 느려지는 건가?"
결론부터 말하면 사용자 로딩이 느려진다.

사용자가 화면을 보기까지 3단계

[1단계] 다운로드    : 서버에서 파일을 받는 시간
[2단계] 파싱(해석)  : 받은 코드를 브라우저가 읽는 시간
[3단계] 실행+렌더링 : 코드 실행해서 화면 그리는 시간

번들 사이즈가 크면 3단계 전부 느려진다.

구체적으로

1단계: 다운로드 느려짐

100 KB → 0.1초 / 500 KB → 0.5초
와이파이에서는 차이 적지만, 지하철 4G에서는 체감 엄청남

2단계: 파싱 느려짐

100 KB 읽기 → 50ms / 500 KB 읽기 → 250ms
이 시간 동안 사용자는 빈 화면 봄

3단계: 실행+렌더링 느려짐

JS 코드가 실행되어야 React 컴포넌트가 화면에 그려짐
코드 많을수록 실행 시간도 길어짐

비교

번들 100 KB:
다운로드(0.1초) → 파싱(0.05초) → 실행(0.05초) = 총 0.2초 ⚡

번들 500 KB:
다운로드(0.5초) → 파싱(0.25초) → 실행(0.2초) = 총 0.95초 😑

번들 2 MB:
다운로드(2초) → 파싱(1초) → 실행(0.5초) = 총 3.5초 😱 → 이탈!

빌드 속도는?

번들 사이즈가 커도 빌드 속도에는 큰 영향 없다.
빌드 속도는 파일 갯수나 번들러 종류(Webpack vs Vite)에 더 영향받는다.

빌드 속도   → 개발자가 기다리는 시간 (번들 사이즈 영향 적음)
사용자 로딩 → 사용자가 기다리는 시간 (번들 사이즈 영향 큼 ⭐)

🧠 Day 1~4 연결 지도

Day 1: 개발 → 빌드 → 배포, .env는 서버마다 따로
           ↓
Day 2: 빌드하면 컴파일 + 번들링 + 최적화 + 정적 생성
           ↓
Day 3: 브라우저가 번들링된 파일을 받아서 캐시, CDN으로 속도 향상
           ↓
Day 4: 번들링이 없으면 요청 50번, 있으면 4번
       Tree Shaking으로 안 쓰는 코드 제거
       번들 사이즈가 크면 다운로드+파싱+실행 전부 느려짐

→ 전부 "코드를 사용자에게 빠르고 효율적으로 전달"이라는 하나의 목적

🎯 오늘 배운 것 최종 정리

  1. 번들링 = 파일을 묶어서 네트워크 요청 횟수를 줄이는 것
  2. 번들러 3가지: Webpack(만능, Next.js 기본), Vite(빠름), esbuild(초고속)
  3. Tree Shaking = 안 쓰는 코드 자동 삭제 → named import 써야 작동
  4. 번들 사이즈 확인: yarn build 로그, bundle-analyzer
  5. 흔한 실수: moment.js, lodash 전체 import, 아이콘 전체 import
  6. 네트워크 = 컴퓨터끼리 데이터 주고받는 통로 (브라우저 동작 전체가 아님)
  7. 번들 사이즈 크면 → 다운로드 + 파싱 + 실행 전부 느려짐 → 사용자 로딩 길어짐

💭 회고

이번 Day 4에서 가장 큰 깨달음은 "import 한 줄이 번들 사이즈를 좌우한다" 는 것이다.

import _ from 'lodash'          // 70 KB
import { debounce } from 'lodash'  // 3 KB

이 한 줄 차이가 사용자 로딩 속도에 영향을 준다니.
지금까지 아무 생각 없이 import 해왔는데, 앞으로는 의식적으로 named import를 쓸 것이다.

그리고 "네트워크"라는 단어를 정확히 몰랐는데, 이번에 확실히 잡았다.
"컴퓨터끼리 데이터를 주고받는 통로". 단순하지만 이 한 문장이 앞으로 배울 HTTP, TCP/IP, DNS 개념의 기초가 된다.


📚 다음 학습 예고

  • Day 5: 개발 서버 vs 프로덕션 서버의 차이
  • HMR(Hot Module Replacement): 저장하면 자동 새로고침 되는 이유
  • 소스맵(Source Map): 압축된 코드에서 에러 찾는 마법

#프론트엔드 #번들링 #Webpack #Vite #TreeShaking #번들사이즈 #2년차개발자 #기초다시쌓기

profile
✨🌏확장해 나가는 프론트엔드 개발자입니다✏️

0개의 댓글