
안녕하세요! 👋 서운입니다!
퍼블리싱만 하던 시절, 제가 처음 공부한 프레임워크는 Vue였습니다.
그때는 회사 동료의 권유로 강의를 듣기 시작했는데… 솔직히 집중도는 낮았고, CS 전공자가 아니었기에 프레임워크가 어떻게 동작하는지 전혀 알지 못했죠.
그냥 “남들이 쓰니까 나도 써야지” 수준이었고,
내부에서 어떤 일이 벌어지는지는 관심도 없었습니다.
지금은 그나마
.vue나 .tsx 파일이 번들러를 거쳐 예쁘게 정리돼서 브라우저에 뜨는 거 아닐까?”
정도는 짐작하지만,
누군가 “번들링이 뭔지 설명해봐”라고 한다면 막막합니다.
그래서 이번에 번들링과 트랜스파일링을 정리해서
“왜 알아야 하는지, 어떻게 동작하는지”를 확실히 해두려 합니다.
번들링(Bundling): 여러 개의 파일을 하나로 포장하는 작업
→ 쇼핑한 물건을 장바구니에 담아 한 봉투로 묶는 것
→ 수많은 JS/CSS/이미지 파일을 묶어 브라우저가 한 번에 가져오게 함
트랜스파일링(Transpiling): 최신 언어를 옛날 언어로 번역하는 작업
→ 최신 JS 문법(let, async/await)을 구형 브라우저도 알아듣는 문법으로 변환
→ 현대 한국어를 옛날 한글체로 번역하듯 의미는 같지만 형태를 바꾸는 것
제 나름대로 한문장으로 정의가 되게끔 해서 정리를 했습니다.
결국
우리가 만약 모회사에 초반입사를 했다고 가정을 해볼게요.
github에 올라가 있는 코드를 받고 보통의 프론트엔드개발이면 해당 코드를 local서버에서 돌릴수 있게 해당 디렉토리위치에서 터미널 명령어npm install을 입력하게 될겁니다.(패키지 매니저는 npm/pnpm/yarn이 대체 가능, 참고: npx는 패키지 실행 용도)그 후 일어나는 일들을 순차적으로 정리를 한번 했어요!
package.json을 읽는다node_modules/
├── react/ # 1차 의존성
├── axios/ # 1차 의존성
│ └── node_modules/
│ └── follow-redirects/ # 2차 의존성
npm 캐시나 레지스트리에서 .tgz(압축 패키지) 파일을 다운로드합니다.
압축을 풀어서 node_modules/ 안에 설치합니다.
설치 도중에 "scripts" 속성에 정의된 preinstall, install, postinstall 스크립트가 있으면 실행됩니다.
위 내용을 간단하게 아래로 정리해볼수 있을 것 같습니다.
src/main.ts 등 진입점에서 의존성 그래프 생성TS/JSX/ESNext/SASS 등을 브라우저/런타임 호환 코드로 변환(Babel/tsc 등)
예전 회사에서 퍼블리싱을 할 때는 외주 업체 요구사항에 맞춰 구형 브라우저 호환성을 직접 챙겨야 했습니다.
하지만 프레임워크를 사용하면 이런 작업을 트랜스파일링이 대신 처리해주기 때문에, 개발자가 일일이 맞출 필요가 줄어듭니다.
즉 현대 자바스크립트(ES6+) 문법은 최신 브라우저에서는 잘 동작하지만,
구형 브라우저(예: IE11)에서는 실행되지 않기 때문에 그 역할을 해주는 것이 트랜스파일링 입니다.
아래는 우리가 평소에 쓰는 ES6코드가 어떻게 변환되는지 과정을 통한 예시 입니다.
// ES6 화살표 함수 & let
let numbers = [1, 2, 3];
let doubled = numbers.map(n => n * 2);
console.log(doubled); // [2, 4, 6]
👉 최신 크롬, 파이어폭스에서는 문제없이 실행됩니다.
하지만 IE11에서는 화살표 함수(=>), let을 이해하지 못해 에러가 납니다.
"use strict";
var numbers = [1, 2, 3];
var doubled = numbers.map(function (n) {
return n * 2;
});
console.log(doubled); // [2, 4, 6]
👉 이렇게 변환되면 구형 브라우저도 이해 가능합니다.
ES6의 Promise, Array.includes 같은 기능은 단순히 문법 변환만으로는 안 됩니다.
이럴 땐 polyfill을 주입해야 합니다.
import "core-js/stable";
import "regenerator-runtime/runtime";
👉 이런 polyfill 덕분에, 브라우저가 모르는 기능도 사용할 수 있게 됩니다.
트랜스파일링은 문법만 변환합니다.
하지만Promise,Array.includes처럼 아예 기능 자체가 없는 경우에는 트랜스파일링만으로 해결되지 않습니다.이럴 때 필요한 것이 바로 Polyfill입니다.
Polyfill은 브라우저나 실행 환경이 아직 지원하지 않는 기능을 흉내 내어 동작하게 해주는 코드 조각입니다.말 그대로 “틈새를 메우는 폼(Poly-fill)” 역할을 합니다.
최신 자바스크립트 기능이 구형 브라우저에서는 없을 수 있는데, 그 “빈 공간”을 채워서 마치 원래 있었던 것처럼 쓸 수 있게 해주는 거죠.
최신 JS에는 includes 메서드가 있지만, IE 같은 구형 브라우저는 이걸 모릅니다.
// 최신 문법
['a', 'b', 'c'].includes('b'); // true
👉 IE11에서는 에러 발생
Polyfill을 추가하면, includes가 없는 환경에서 직접 구현해줍니다
if (!Array.prototype.includes) {
Array.prototype.includes = function (search) {
return this.indexOf(search) !== -1;
};
}
→ 이제 구형 브라우저에서도 includes를 쓸 수 있음.
IE11에는 Promise 객체가 없습니다.
Polyfill을 추가하면 다음처럼 구현된 코드가 자동으로 삽입됩니다:
import "core-js/stable";
import "regenerator-runtime/runtime";
→ 이렇게 하면 Promise, async/await 같은 기능이 IE11에서도 동작합니다.
- 트랜스파일링 : 최신 문법을 구형 문법으로 변환 → 브라우저 호환성 확보 (예: let → var)
- Polyfill : 브라우저가 아예 모르는 기능을 흉내 내서 추가해주는 것 (예: Promise, includes)
- 이 과정 덕분에
npm run build로 뽑아낸 번들이 모든 브라우저에서 안전하게 실행됩니다.- 둘 다 합쳐야 완전한 호환성 확보 가능
프론트엔드 코드가 커지면, 파일을 여러 개로 나눠 관리해야 합니다.
이때 서로 다른 파일 간 코드를 어떻게 불러오고, 실행 시 묶을지 정해주는 방식이 바로 모듈 시스템 입니다.
require/module.exports, 또 다른 파일은 import/export로 되어 있어요.type: "module" 옵션, Babel, 번들러 설정이 필요해지는 거예요.npm install로 가져오는 패키지가 CJS일 수도, ESM일 수도 있기 때문이죠CommonJS와 ES Module을 비교하는 이유는 단순히 문법 차이를 아는 데 그치지 않습니다.
두 방식은 자바스크립트 역사 속에서 차례로 등장했고, 지금도 공존하고 있기 떄문에 실무에서 혼란의 원인이 됩니다.또한 우리가 사용하는 패키지와 번들러가 왜 이런 두 형식을 모두 지원해야 하는지 이해하려면, 이 비교가 꼭 필요합니다.
node_modules 안을 열어보면 CommonJS 문법을 확인할 수 있어요.'use strict';
if (process.env.NODE_ENV === 'production') {
module.exports = require('./cjs/react.production.min.js');
} else {
module.exports = require('./cjs/react.development.js');
}
👉 여기서 module.exports랑 require 보이죠?
React도 배포된 빌드 파일은 CommonJS 형태로 제공됩니다.
// math.js
function add(a, b) {
return a + b;
}
module.exports = add;
// main.js
const add = require("./math");
console.log(add(2, 3)); // 5
👉 CommonJS (CJS)란 자바스크립트 모듈을 작성하고 불러오는 방식(규격) 이에요.
즉, require와 module.exports 문법을 사용하는 게 바로 CommonJS 스타일 코드입니다.
require()가 호출되면, 그 순간 바로 파일을 읽고 실행합니다.import, export 키워드 사용// math.js
export function add(a, b) {
return a + b;
}
// main.js
import { add } from "./math.js";
console.log(add(2, 3)); // 5
👉 ES Module은 표준 모듈 형식이에요.
즉, import와 export 문법을 사용하는 게 ESM 스타일 코드라는 뜻입니다.
| 구분 | CommonJS (CJS) | ES Module (ESM) |
|---|---|---|
| 문법 | require, module.exports | import, export |
| 로딩 방식 | 동기 (실행 시 불러옴) | 비동기 (병렬 로딩 가능) |
| 주로 사용 | Node.js (옛날) | 브라우저 & Node.js (최신) |
| 등장 시기 | 2009년경 | 2015년 (ES6) |
앞에서 CommonJS(CJS)와 ES Module(ESM)을 왜 비교해야 하는지, 그리고 두 체계가 공존하는 이유를 살펴봤습니다, 이 두개의 형식중점에 있는 require, import를 비교해보려고 합니다.
“require vs import” 차이를 꼭 알아야 하는 이유는 단순히 문법 차이 때문이 아니라, 실제 프로젝트 세팅, 에러 상황, 최적화와 직결되기 때문이에요.
// 어떤 패키지는 이렇게 해야 불러와지고
const express = require("express"); // CJS
// 어떤 패키지는 이렇게 해야 불러와집니다
import React from "react"; // ESM
"SyntaxError: Cannot use import statement outside a module"같은 에러에 막히게 됩니다.package.json에 "type": "module"을 명시해야 합니다.import를 쓰면 동작하지 않죠.👉 따라서 “require vs import” 차이를 이해하면 빌드 도구 설정 문제를 빠르게 파악할 수 있습니다.
👉 성능 최적화 관점에서 import 방식이 유리합니다.
결국 우리가
require와import차이를 알아야 하는 이유는 단순히 문법 때문이 아닙니다.
우리가 사용하는 패키지가 CJS인지 ESM인지에 따라 에러가 날 수 있고,
번들러와 런타임 설정에도 직접적인 영향을 주며,
나아가 최적화 가능 여부까지 달라지기 떄문입니다.
| 구분 | require (CJS) | import (ESM) |
|---|---|---|
| 문법 | const pkg = require("pkg") | import pkg from "pkg" |
| 동작 시점 | 런타임(실행 중) 모듈 불러옴 | 컴파일 시점에 모듈 구조 파악 |
| 로딩 방식 | 동기 로딩 → 호출 시 즉시 실행 | 비동기 로딩 → 병렬 처리 가능 |
| 최적화 | Tree Shaking 불가 (사용하지 않는 코드도 포함) | Tree Shaking 가능 (안 쓰는 코드 제거) |
| 환경 | Node.js 기본(옛날 방식) | 브라우저 표준, 최신 Node.js 지원 |
| 대표 사례 | const express = require("express") | import React from "react" |
require는 Node.js에서 오래도록 쓰인 동기 로딩 방식이고, import는 현대 자바스크립트 표준인 비동기 로딩 방식입니다.
결국 두 방식은 "실행 시점에 모듈을 불러오느냐, 아니면 빌드 단계부터 모듈 관계를 파악하느냐"의 차이로 요약할 수 있습니다.
동기, 비동기 로딩 차이를 알게되면 프로젝트 성능, 에러 상황, 번들링 최적화가 어떻게 진행이 되는지 연결되어 생각할수 있습니다.
require() 가 실행되는 순간, 그 모듈이 로딩될 떄까지 나머지 코드들이 멈춥니다.import를 쓰려 했는데 Node.js설정이 CJS라서 "SyntaxError: Cannot use import statement outside a module"에러가 발생합니다.require로 불러왔는데 브라우저에서 동작 안하는 경우가 있습니다.👉 이런 문제들을 빠르게 파악하려면 동기/비동기 로딩 차이를 이해하고 있어야 합니다.
// CommonJS - 동기 로딩
const fs = require("fs"); // 파일 로딩이 끝날 때까지 다음 줄 실행 안 됨
console.log("이 줄은 require가 끝난 후 실행됨");
// ES Module - 비동기 로딩
import { readFile } from "fs/promises";
async function run() {
const data = await readFile("text.txt", "utf-8");
console.log(data);
}
run();
| 구분 | 동기 로딩 (CJS / require) | 비동기 로딩 (ESM / import) |
|---|---|---|
| 실행 방식 | 직렬(순서대로 실행) | 병렬(동시에 실행 가능) |
| 코드 진행 | 이전 작업 끝날 때까지 멈춤 | 기다리는 동안 다른 코드 실행 가능 |
| 환경 | Node.js 초기 기본 | 브라우저 표준, 최신 Node.js |
| 성능 | 작은 코드에는 무난 | 대규모 앱, 네트워크 요청 많은 경우 유리 |
| 최적화 | Tree Shaking 불가 | Tree Shaking 가능 |
CommonJS의 require는 동기 로딩이기 때문에 서버 환경에선 괜찮지만, 브라우저에서는 성능 병목이 생깁니다.
반대로 ES Module의 import는 비동기 로딩이 가능해 브라우저 환경에 적합하며, 빌드 최적화(Tree Shaking)까지 지원합니다. 결국 최신 어플리케이션을 만든다고 하면 비동기 로딩을 지양하는 것이 환경과 성능 측에서 좋다고 생각이 듭니다.
자바스크립트는 원래 브라우저 전용 언어로 시작했습니다.
하지만 Node.js가 등장하면서 서버 환경에서도 자바스크립트를 쓰게 되었고, 그 과정에서 모듈 시스템(하나의 큰 프로그램을 여러 개의 독립적이고 재사용 가능한 부분, 즉 모듈(module)로 분리하여 관리하는 방식)이 두 갈래로 발전했씁니다.
- 브라우저: HTML 기반, 네트워크 요청을 통해 스크립트를 불러오는 구조 -> 비동기 로딩(ESM)에 최적화
Node.js: 파일 시스템 기반, 빠른 로컬 파일 접근 가능 -> 동기 로딩(CJS) 도 큰 무리 없음👉 그래서 같은 자바스크립트라도 어느 환경에서 실행하느냐에 따라 모듈 동작 방식이 다릅니다.
실무에서는 우리가 작성한 코드가 브라우저에서 실행될 수도 있고, Node.js(백엔드, 빌드 도구, 번들러)에서 실행될 수도 있기 떄문에, 두 환경의 차이를 정확히 이해하는 것이 중요합니다, 그래야 사용 가능한 문법과 설정을 달리 사용할수 있기 때문입니다.
<script type="module"> 속성을 사용하면 import/export 문법을 인식할 수 있습니다.require, module.exports)는 브라우저가 직접 이해하지 못합니다. -> 반드시 번들링/트랜스파일링 이 필요하죠<!-- 브라우저 ESM 예시 -->
<script type="module">
import { add } from "./math.js";
console.log(add(2, 3));
</script>
👉 브라우저는 네트워크 요청을 통해 모듈을 가져오기 때문에, 비동기 로딩 인 ESM이 적합합니다.
require/module.exports 문법이 지금도 널리 쓰이고 있습니다.package.json에 "type":"module"을 설정해야 import/export를 쓸 수 있습니다.// Node.js - CommonJS
const fs = require("fs");
console.log("CJS:", fs.existsSync("app.js"));
// Node.js - ESM
import fs from "fs";
console.log("ESM:", fs.existsSync("app.js"));
👉 즉, Node.js에서는 CJS와 ESM이 모두 동작하지만, 프로젝트 설정에 따라 어떤 걸 쓰는지가 달라집니다.
| 구분 | 브라우저 | Node.js |
|---|---|---|
| 기본 지원 | ESM(import/export) | CJS(require/module.exports) |
| CJS 사용 | ❌ 직접 지원 불가 → 번들링 필요 | ✅ 기본 지원 |
| ESM 사용 | ✅ <script type="module"> | ✅ ("type": "module" 또는 .mjs) |
| 적합한 이유 | 네트워크 요청 기반 → 비동기 로딩 유리 | 서버 환경 파일 접근 빠름 → 동기 로딩도 무리 없음 |
브라우저는 기본적으로 ESM만 이해하고, CommonJS는 번들러 없이는 사용할 수 없습니다.
반대로 Node.js는 원래 CJS만 지원했지만, 최신 버전에서는 ESM도 지원합니다.
따라서 브라우저 = ESM 중심, Node.js = CJS 중심 + ESM 지원이라는 차이가 있습니다.
브라우저 환경에서는 모듈이 많아질수록 네트워크 요청이 늘어나 병목 현상이 발생합니다.
번들러는 의존성 그래프를 분석해 하나의 번들 파일로 합쳐주기 떄문에, 브라우저는 최소한의 요청만으로 앱을 실행할 수 있습니다.조금 더 자세한 내용은 아래 번들러 챕터에서 서술하도록 하겠습니다!!
import하는지 전부 추적합니다.bundle.js같은 파일만 요청하면 되므로/src
├── utils.js
├── api.js
├── component.js
└── main.js
👉 브라우저가 각 파일을 하나하나 요청해야 함 (네트워크 요청 증가)
/dist
└── bundle.js
👉 브라우저는 bundle.js 하나만 요청하면 됨 (네트워크 요청 최소화)
번들링이 필요한 가장 큰 이유는 네트워크 요청을 최소화하기 위해서 입니다.
작은 모듈 수백 개를 각각 불러오는 대신, 번들러가 하나의 파일로 묶어주면 브라우저는 빠르고 효율적으로 코드를 실행할 수 있습니다.

트랜스파일링이란 최신 자바스크립트 문법(ES6+, ESNext)을 하위 버전(ES5 등)으로 변환하는 과정을 말합니다.
쉽게 말해, 최신 언어를 구형 환경에서도 동작하도록 번역하는 작업입니다.
1. Babel
("target":"ES5")에 따라 ESNext JS -> 구버전 JS 코드로도 트랜스파일링이 가능합니다.@babel/preset-env: 환경별로 필요한 문법 변환/폴리필 자동 적용@babel/preset-react: JSX → JS 변환@babel/preset-typescript: TS → JS 변환babel-loader (Webpack)rollup-plugin-babeloptional chaining, nullish coalescing도 Babel 덕분에 표준화되기 전부터 쓸 수 있었음.Babel은 esbuild, SWC보다 속도는 느릴 수 있지만,
- 구형 브라우저까지 커버하는 호환성
- 방대한 플러그인 생태계
- 세밀한 설정 제어력
- 오래된 프로젝트와 번들러 생태계의 기본 통합성
덕분에 여전히 많이 쓰이고 있습니다.
즉, 새로운 도구들이 속도와 단순함을 강점으로 한다면, Babel은 안정성과 범용성을 강점으로 한다고 볼 수 있습니다.
obj?.prop) 같은 문법도 Babel을 거치면 안전하게 사용할 수 있습니다.👉 Babel은 크게 세 단계를 거칩니다.
const sum = (a, b) => a + b; → 트리 구조로 분석@babel/plugin-transform-arrow-functions는 화살표 함수를 일반 함수로 변환let, const -> varPromise (구형 브라우저에 없음)Array.prototype.includesasync/await (regenerator-runtime 필요)core-js, regenerator-runtime을 함께 사용해 자동으로 polyfill 삽입@babel/preset-env → 브라우저 환경에 맞춰 필요한 변환/폴리필만 자동 적용@babel/plugin-transform-react-jsx → React JSX 문법을 React.createElement 코드로 변환됩니다.Webpack 설정에서 babel-loader 사용npm run build 할 때 자동으로 트랜스파일링이 적용됨// ES6 화살표 함수 & const
const sum = (a, b) => a + b;
"use strict";
var sum = function sum(a, b) {
return a + b;
};
👉 여기서 const → var, 화살표 함수 → 일반 함수로 변환된 것을 볼 수 있습니다.
트랜스파일링: 최신 문법을 하위 버전으로 변환 → 브라우저 호환성 확보
Babel은 단순히 “최신 문법을 옛날 문법으로 바꿔주는 도구”를 넘어서,
(1) 파싱 → (2) 변환 → (3) 코드 생성의 과정을 거쳐 동작하며,
플러그인과 프리셋을 통해 우리가 어떤 환경(브라우저, Node.js)을 타겟으로 할지 맞춤 설정할 수 있습니다.
덕분에 개발자는 최신 문법을 마음껏 활용하면서도, 구형 브라우저 호환성을 확보할 수 있습니다.트랜스파일링: 최신 문법을 하위 버전으로 변환 → 브라우저 호환성 확보
👉 이 과정을 통해 우리가 작성한 최신 자바스크립트 코드가 구형 브라우저에서도 안전하게 실행됩니다.
번들링(Bundling) 이란 프로젝트 안에 흩어져 있는 여러 모듈 파일을 하나(또는 몇 개)의 큰 파일로 합치는 과정을 말합니다.
👉 쉽게 말해, 수많은 JS, CSS, 이미지 모듈들을 “하나의 묶음”으로 만들어 브라우저가 효율적으로 불러올 수 있게 해주는 작업입니다.
자바스크립트 프로젝트가 커지면 파일이 수십, 수백 개로 나뉘게 됩니다.
이 파일들을 브라우저가 각각 개별 요청으로가져온다면 어떤 문제가 생길까요?
- 네트워크 요청이 많아져 로딩 속도 저하
- 브라우저가 동시에 처리할 수 있는 요청 수(병렬 요청 제한)에 걸림 -> 네트워크 병목이 발생하게 됩니다.
- 사용자는 화면이 늦게 뜨거나, 기능이 지연되는 경험을 하게 됩니다.
- 브라우저 환경에서는 단순히
<script type="module">로 모든 ESM 파일을 불러오는 방식만으로는 한계가 있습니다.
👉 이런 문제들을 해결하려는 핵심이 바로 번들링(Bundling)입니다.
👉 그래서 번들러가 의존성 그래프를 분석 → 하나(또는 몇 개)의 파일로 묶어서 제공해주는 겁니다.
/src
├── utils.js
├── api.js
├── component.js
└── main.js
👉 브라우저는 여러 파일을 각각 요청해야 합니다.
/dist
└── bundle.js
👉 브라우저는 bundle.js 하나만 요청하면 됩니다.
번들링은 단순히 파일을 합치는 것을 넘어서,
- "의존성 관리"
- "코드 최적화(Tree Shaking, 압축, 코드 스플리팅)"
- "개발 편의 기능(HTR, 빌드 환경 통합)
까지 담당하는 중요한 과정입니다.
다양한 번들러가 존재하지만, 프로젝트의 성격에 따라 적합한 도구를 선택하는 것이 핵심입니다."
번들링이란 단순히 "여러 파일을 합치는 것"으로만 끝나지 않습니다.
사실 그 안에는 진입점 탐색 -> 의존성 그래프 생성 -> 변환 -> 묶음 출력이라는 일련의 과정이 숨어 있어요.
이 과정을 이해하면, 우리가 흔히 접하는 로더(loaders), 플러그인(plugins), 그리고 Tree Shaking 같은 개념도 자연스럽게 연결됩니다.아래는 그 동작 과정을 순서대로 정리해봤습니다.
번들러는 프로젝트의 시작 파일(엔트리 포인트)에서 탐색을 시작합니다.
예: src/main.js 또는 src/index.tsx
이 파일을 기준으로 import, require를 따라가며 어떤 모듈들이 필요한지 추적합니다.
👉 즉, “어디서부터 읽어야 할까?”라는 출발점 역할을 하는 게 엔트리입니다.
👉 이 그래프 덕분에 번들러는 프로젝트 전체 구조를 파악할 수 있고, 불필요한 모듈을 제거하거나 최적화할 수 있습니다.
babel-loader: JSX/ESNext → 브라우저 호환 JSts-loader: TypeScript → JavaScriptcss-loader, sass-loader: CSS/SCSS → JS에서 불러올 수 있게 변환👉 즉, 로더는 파일 확장자별로 어떻게 읽고 변환할지 정의하는 도구입니다.
dist/bundle.js, dist/chunk-vendors.jsHtmlWebpackPlugin → HTML에 번들 자동 삽입MiniCssExtractPlugin → CSS 파일 별도 분리👉 플러그인은 말 그대로 “추가 기능 확장 도구”라, 번들링 결과물을 원하는 형태로 커스터마이징할 수 있게 해줍니다.
아래는 정적 분석 가능한 코드 예시 (ESM) 입니다
// utils.js
export function add(a, b) { return a + b; }
export function subtract(a, b) { return a - b; }
// main.js
import { add } from "./utils";
console.log(add(2, 3));
👉 subtract 함수는 사용되지 않았으므로 최종 번들에 포함되지 않습니다.
아래는 정적 분석이 불가능한 코드 예시 (CJS)입니다.
// main.js
const moduleName = "./math.js";
const math = require(moduleName);
console.log(math.add(2, 3));
👉 require 안에 변수가 들어가 있으니까, 실행해보기 전에는 어떤 파일을 가져올지 알 수 없음
moduleName 값이 실행 도중에 바뀔 수도 있기 때문에,
정적 분석 단계에서는 “math.js를 쓴다”는 걸 확정할 수 없습니다.
→ 이런 경우는 Tree Shaking 같은 최적화가 불가능해요.
Entry → Dependency Graph → Transform(Loaders) → Bundle Output(Plugins)
최종 단계에서 Tree Shaking 같은 최적화로 크기를 줄이고 성능을 높이죠
즉, 번들러는 단순한 “파일 합치기 도구”가 아니라, 전체 코드를 분석·변환·최적화하는 빌드 파이프라인입니다.
아래는 위 번들러 동작과정을 다이어그램으로 이해하기 쉽도록 그려봤습니다.

처음으로 진짜 내가 뭘 모르는지 하나하나 물어보고 블로그 찾아보면서 정리하며 적어본 포스트네요, 처음 스터디 포스트라 그런가 내용도 많고 내가 매일 쓰던 기본 개념들중 모르는 부분이 너무 많아 하나하나씩 다 GPT에게 물어보고 맞는지 틀린지 블로그를 보며 정리하느라 시간도 오래 걸리고 개념정리를 이번 블로그를 쓰면서 확실히 이해를 하는 과정을 거쳤습니다.
여기까지 번들링과 트랜스파일링의 기본 개념,
그리고 npm install -> build 과정 속에서 어떤 일이 일어나는지를 알아봤습니다!
정리하자면,
npm install을 입력하면 npm cli이 트랜스파일링과 번들링이 어떤식으로 진행되는지👉 즉, 우리가 매일처럼 쓰는 npm run build 뒤에는 "호환성 확보"와 "성능 최적화" 라는 두 축이 동시에 작동하고 있는 것을 알수 있었습니다.
다음 2부에서는
등을 정리해볼 예정입니다. 🚀
JavaScript 번들러의 이해 — (1) JavaScript 모듈
JavaScript 번들러의 이해 — (3) 번들러 개론
JavaScript 번들러의 이해 — (4) Webpack 및 다른 번들러들
webpack
중간에 확인해주시고 오타 지적, 복수내용 확인해주신
너무 너무 감사합니다!!🙏
번들러 완벽정리 ㅇㅅ ㅇ ,,!