안녕하세요! 👋 서운입니다!
저번에 못다한 번들러와 트랜스파일링을 마무리 하도록 하겠습니다!
앞에서 배운 것처럼,
트랜스파일러(Transpiler) → 최신 문법을 구형 환경에서도 동작하게 변환
번들러(Bundler) → 흩어진 모듈을 하나(또는 몇 개)의 파일로 묶음
👉 그런데 실제 프로젝트에서는 이 둘이 따로 놀지 않고, 항상 함께 사용됩니다.
왜냐하면, 단순히 묶기만 하면 최신 문법이 그대로 들어있을 수 있고, 변환만 하면 모듈이 흩어진 채일 수 있기 때문이죠.
함께 사용하는 그 조합에 대한 예시를 보여드릴게요
Webpack이 프로젝트 전체 모듈을 탐색하고,Babel이 그 과정에서 각 파일을 ES5로 변환// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.js$/, // .js 파일을 만나면
exclude: /node_modules/,
use: {
loader: "babel-loader", // Babel로 변환
},
},
],
},
};
esbuild(빠른 트랜스파일링) + Rollup(최적화 번들링) 조합이라고 볼 수 있습니다.tsc만 쓰면 단순히 JS 변환까지만 → 번들링은 안 됨esbuild 기반으로 TS를 바로 변환해주기 때문에 더 간단해졌습니다.| 구분 | 트랜스파일러 (Babel, tsc, esbuild, SWC) | 번들러 (Webpack, Rollup, Vite) |
|---|---|---|
| 목적 | 최신 문법 변환 → 구형 환경 실행 가능 | 여러 모듈 묶기 → 네트워크 요청 최소화 |
| 초점 | 문법/호환성 | 모듈 관리/최적화 |
| 산출물 | 변환된 JS 파일 | 하나(또는 여러 개)의 번들 파일 |
| 예시 | Babel로 ES6 → ES5 변환 | Webpack으로 bundle.js 생성 |
👉 그래서 둘은 “변환 + 묶음” 이라는 연속된 파이프라인으로 작동합니다.
번들러와 트랜스파일러는 잘만 쓰면 강력하지만, 프로젝트가 커지면 빌드 속도와 번들 크기 문제가 생깁니다.
이를 해결하기 위해 자주 쓰이는 최적화 기법들을 정리해봤습니다.
babel-loader에서 cacheDirectory: true옵션을 켜면, 변환된 결과를 캐시에 저장// webpack.config.js
{
loader: "babel-loader",
options: {
cacheDirectory: true,
},
}
node_modules 같은 외부 라이브러리는 이미 변환된 코드 -> 트랜스파일 대상에서 제외include해서 불필요한 변환을 줄임{
test: /\.js$/,
include: path.resolve(__dirname, "src"),
exclude: /node_modules/,
use: "babel-loader",
}
splitChunks설정, 혹은 Vite의 dynamic import를 활용해 필요한 시점에만 코드 로드// 필요한 시점에만 import
import("./Chart").then(module => {
const Chart = module.default;
new Chart().render();
});
👉 초기 로딩 속도 ↓, 페이지 전환 후 필요한 코드만 로딩
ESM(import/export) 기반에서만 정적 분석이 가능// utils.js
export function add(a, b) { return a + b; }
export function subtract(a, b) { return a - b; }
// main.js
import { add } from "./utils"; // subtract는 사용 안 함
👉 최종 번들에서는 subtract 함수가 제거됨
import()문법으로 로딩async function openAdminPage() {
const { default: Admin } = await import("./AdminPage");
new Admin().render();
}
👉 초기 번들을 작게 유지하면서, 필요할 때만 로드
이렇게 실무에서 주로 쓰이는 기법들을 확인해보았고, 다음으로 추가적인 최적화 기법들을 소개해 드리도록 하겠습니다. 사실 모든 프로젝트들이 대규모 프로젝트일리는 없고 모든 기법들을 최적화 시키지 않아도 되겠지만 알아두고 프로젝트의 규모가 커질수록 아래 기법들을 추가시키면서 사용자 경험을 최적화 시킬 좋은 기회가 생길테니까요!
imagemin, svgo 등)bundle.abc123.js<link rel="preload">로 미리 로드thread-loader, esbuild-loader같은 툴로 트랜스파일링 속도 가속
최적화 전략
│
├── 빌드 속도 줄이기
│ ├── 캐싱 (cacheDirectory)
│ ├── exclude/include
│ ├── 코드 스플리팅
│ └── 멀티 스레드/병렬 처리
│
├── 번들 크기 줄이기
│ ├── Tree Shaking
│ ├── Dynamic Import
│ ├── 코드/리소스 분리 (lazy load)
│ └── 압축 (minify, 이미지 최적화)
│
└── 배포/런타임 최적화
├── CDN 활용
├── 캐시 전략 (hash, cache-control)
└── Preload / Prefetch
번들링과 트랜스파일링은 처음 접하면 "그냥 빌드하면 알아서 해주는 거 아닌가?" 싶었던 개념입니다. 저도 초반에는 그랬구요.
하지만 실무에서 직접 프로젝트를 진행하거나, 해당 내용을 공부하면서 이 개념을 모르는 상태와 이해한 상태의 차이를 크게 느꼈습니다. 아래는 제가 개인적으로 생각하는, 그리고 다른분들의 블로그를 보면서 꺠달은 인사이트들을 정리해봤습니다.
npm run build에서 뭔가 에러가 나면, 무조건 구글링, 인공지능에게 근본 없이 질문 → “설정이 꼬였나?” 막연한 추측만 가능require vs import 에러를 만나면 왜 그런지 설명조차 못 하고 복붙으로 해결Tree Shaking, Dynamic Import, 코드 스플리팅 같은 최적화 방법을 바로 적용 가능번들링과 트랜스파일링을 공부한다는 건 단순히 도구를 배우는 게 아니다 라는 생각을 했습니다.
저는 이제 "빌드 과정은 블랙박스"가 아니라,
내가 이해하고 선택할 수 있는 과정이라는 걸 체감했습니다.
결국 번들링과 트랜스파일링은 "프론트엔드 개발자가 도구를 능동적으로 활용할 수 있느냐"를 가르는 중요한 지식중 하나라고 생각했습니다.
조금 시간이 걸렸지만, 번들링과 트랜스파일링1,2부로 전체적으로 정리하는 시간을 한번 갖어보는 시간은 저에게 너무 유익했네요, 2부에서는 실제로 번들링과 트랜스파일링이 실제로 어떻게 쓰이고 있는지, 어떤식으로 최적화 시켜서 써야 가장 효율성이 좋은지정도를 정리해본 것 같네요.
다음번엔 조금 더 좋은 주제로 블로그 작성을 하도록 하겠습니다.
긴글 읽어주셔서 감사합니다!
이상한 부분, 오타, 추가해야될 내용들 지적해주시면 환영입니다!!
참고한 블로그 내용