안녕하세요 서운입니다!
이번에는 번들링이 진행되는 과정에대해 자세히 살펴보려고합니다.
저번 글에서 번들링이 무엇인지, 어떤 배경에서 등장했는지에 대해 먼저 다뤘는데요. 이번에는 그 연장선으로 “번들러가 내부으로 어떤 순서로 일을 처리하는지”에 초점을 맞춰 정리합니다.
제가 이전 글에서 번들링을 “여러 파일을 하나로 포장하는 작업”이라고 설명했던 이유는, 실제로 번들링이 수많은 JS/CSS/이미지(정적 자원)들을 브라우저가 효율적으로 가져오게 만들기 위한 과정이기 때문입니다.
다만 여기서 중요한 포인트는:
이 작업을 위해 번들러는 프로젝트 전체를 훑으며 의존성 관계를 분석하고, 결과물을 출력합니다.
보통 npm run build 같은 스크립트를 실행하면(내부적으로 webpack/vite/rollup 등 호출), 번들러는 설정 파일에서 Entry Point(진입점) 를 확인하고, 그 지점부터 import를 추적하며 작업을 시작합니다.
번들러는 시작 파일(들) 을 기준으로 출발합니다.
엔트리에서 import/require를 따라가며 파일 위치를 찾는 규칙(확장자, alias, node_modules 우선순위 등)을 적용합니다.
점검 포인트:
import "./style.css" 같은 것도 모듈로 취급하도록 설정되어 있나?리졸브가 끝나면 번들러는 프로젝트에 필요한 모든 모듈을 모아 의존성 그래프를 구성합니다.
점검 포인트:
“왜 이 라이브러리가 결과물에 포함됐지?”
→ 의존성 그래프에 들어왔기 때문
“안 쓰는 코드가 왜 섞여 있지?”
→ 그래프에는 포함됐지만, 최적화(트리 셰이킹)가 충분히 적용되지 않았을 수 있음
즉, 번들러 입장에서 의존성 그래프는 “무엇을 포함할지”를 결정하는 핵심 단위입니다.
여기서부터는 “브라우저가 바로 실행/처리하기 어려운 형태”를 브라우저 친화적인 형태로 바꾸는 단계입니다.
예시를 들어보면:
역할 구분을 깔끔하게 잡으면:
점검 포인트:
의존성 그래프를 기반으로 “어떻게 파일을 나눠서(또는 합쳐서) 출력할지” 결정합니다.
build.rollupOptions.output.manualChunks로 청크 전략을 제어한다고 안내합니다.점검 질문:
대표적으로:
점검 질문:
마지막으로 번들(및 정적 자산)을 디스크에 씁니다.
점검 질문:
특히 Vite같은 도구는 “개발 중”에는 번들을 매번 다시 만들기보다 빠른 피드백을 위해 다른 접근을 하고, 프로덕션 빌드는 Rollup 기반으로 간다고 공식 문서에서 설명합니다.
점검 질문:
그럼 저는 위와 같은 과정을 정리하면서 이런 의문이 들었습니다.
해당 과정 즉 변환 -> 출력 의 단계에서의 비용이 더 비싸지 않을까 라는 생각을 했습니다, 한번 번들링으로 파일들을 묶고 브라우저에서 렌더링하기 위해 다시 그 묶음을 풀어야 한다고 생각이 들었습니다.
위 질문을 AI에게 물었고 이에 따른 비용은 누가/언제 내는 비용으로 쪼개면 결론이 난다는 답변을 받으면서 아래와 같이 정리해주었습니다.
빌드 시점에 번들러가 의존성 그래프를 만들고, 로더로 변환하고, 청크를 나누고, 최적화하고, 결과물을 emit 하는 만큼 CPU/시간 비용이 추가됩니다. 그래서 Webpack도 “빌드/컴파일 성능”을 개선하는 가이드를 따로 둡니다.
즉, “번들링을 안 하면(=빌드 단계에서 그런 작업을 생략하면) 빌드 시간은 더 싸질 수 있다”는 직감은 빌드 비용만 놓고 보면 대체로 맞습니다.
번들링은 보통 CI/배포 파이프라인이 1회 내는 비용이고,
그 결과물은 모든 사용자가 다운로드/실행/캐싱 비용에 영향을 받습니다.
즉, 번들링은 “빌드 비용을 조금 더 내는 대신” 사용자 측 비용을 더 통제하기 쉬운 형태로 바꿉니다.
“번들링 안 함”을 보통 (1) 파일이 더 잘게 쪼개져 있고 (2) 최적화가 약한 상태로 해석하면,
또한 “장기 캐시” 관점에서, 번들러는 콘텐츠 해시로 내용이 바뀐 파일만 갱신되게 만들 수 있습니다. 이건 배포 후 트래픽 비용과 체감 성능에 직접 영향이 큽니다.
React/Vue 앱은 보통 TS/JSX/SFC, CSS 처리 등이 필요해서 어차피 변환(트랜스파일) 단계는 거의 필수입니다(완전한 “무가공 ESM 배포”가 어려움).
Vite도 개발에선 빠르게 하려고 “의존성 프리번들”을 따로 하고(요청 수 감소를 직접 예시로 듭니다), 프로덕션 빌드는 Rollup 기반으로 묶습니다.
번들러가 엔트리에서 import를 따라 의존성 그래프를 만들고, 필요한 모듈을 모아 번들로 묶는다고 웹팩에서 명시하고 있습니다.
여기서 "왜 묶냐?"는 보통 아래 3가지 사용자 비용을 겨냥합니다.
즉, 번들링의 1차 목적은 “파일을 합쳐서”가 아니라 요청/대기 모델을 관리하기 쉽게 만드는 쪽입니다.
여기서 핵심은: 번들링=무조건 한 파일이 아니라, “사용자에게 지금 필요한 것만 먼저 보내기”를 가능하게 하는 청크 전략(스플리팅)입니다.
Webpack 캐싱 가이드는 “콘텐츠가 바뀌지 않으면 결과 파일을 캐시에 유지”하는 구성을 다룹니다.
contenthash는 “콘텐츠가 바뀌면 해시도 바뀐다”는 점을 한국어 가이드가 명시합니다.
즉 번들링 결과물은 장기 캐시를 잘 먹게 만들어서, 사용자 재방문/부분 업데이트 비용을 줄이기 쉽습니다.
여기서 스스로 판정 질문 2개만 던지면 됩니다.
1. 번들링을 안 하면 초기 로드 때 ‘요청 수’가 늘어나는가?
2. 번들링을 안 하면 초기 로드 때 ‘초기 JS 양’이 줄어드는가?
현업에서 결론은 보통 이렇게 정리됩니다:
빌드 비용(변환→출력)은 CI/배포에서 “몇 번” 내는 비용이고,
사용자 비용(다운로드/처리/캐시)은 “모든 사용자”가 내는 비용이라서,
대부분의 서비스는 번들링/스플리팅/캐싱으로 사용자 비용을 관리하는 쪽을 택합니다. (Vite도 개발 단계에서조차 의존성 pre-bundling을 기본으로 둡니다.)
정리하면:
그래서 현업에서 번들링은 “빌드 비용이 들더라도”, 사용자 경험과 운영 효율 측면에서 선택되는 경우가 많습니다.