C.W.K.
Stream
Lesson 01 of 05 · published

Bundle vs No-Bundle — 2026 패러다임

~11 min · tooling, bundler, build

Level 0노드 입문자
0 XP0/40 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"번들링은 브라우저 한계의 우회책으로 시작. 2026 엔 브라우저가 따라잡고 — '기본 번들' 이 요구사항 아닌 습관 됨."

왜 번들링이 존재했지

2010 년대엔 브라우저가 ES 모듈 네이티브 로드 못 했어. 모든 import 문이 별도 네트워크 round-trip; 작은 모듈 100 개면 페이지 로드마다 request 100 개. 번들러 (webpack, browserify, 그 다음 Rollup, esbuild, swc, Vite, Turbopack) 가 이걸 풀었어:

  • Import 그래프 정적 walk.
  • 모든 모듈을 적은 출력 파일들로 concatenate.
  • Minify, 죽은 코드 tree-shake, 옛 브라우저용으로 새 문법 lower.

브라우저 출하용엔 여전히 유용 (HTTP/2 도움, HTTP/3 가 더 도움 — 근데 tree-shaking 은 여전히 진짜). 서버 사이드 Node 코드엔? 대부분 cargo cult.

서버 사이드 Node 는 번들링 안 필요

네 Node 서버가 로컬 디스크에서, in-process, ms 안에 모듈 읽어. 네트워크 없음. Import 당 100ms RTT 없음. "first paint" 예산 없음. 브라우저용 번들러 존재 이유가 적용 안 돼.

그런데 대부분 TypeScript Node 서비스가 어쨌든 번들해, 보통 템플릿이 그래서. 비용: dev 의 빌드 단계, CI 의 빌드 단계, 디버그용 source map, 런타임이 이미 문법 이해해도 transpile pass (Node 22+ 가 모던 JS 네이티브 실행; "옛 Node 위한 transpile" 안 필요).

2026 Node 서비스엔: 그냥 소스 실행. node --experimental-strip-types --env-file=.env server.ts. 빌드 없음, 번들 없음, source map 없음, 문제 없음.

Node 에 여전히 번들할 때

  • Single-executable apps (SEA) — SEA 입력으로 한 파일에 번들 원함. esbuild 또는 bun build 가 이거에 좋음.
  • FaaS 배포 (AWS Lambda, Vercel Functions) — 큰 디렉토리에 deploy target 의 cold-start 페널티; 번들링이 줄임. 일부 프레임워크 (Next.js) 가 내부적으로 함.
  • CLI 를 단일 파일로 배포 — 사용자가 npx your-cli, npm 에서 번들된 한 파일 받음, 네 풀 transitive 트리 안 끌어옴.
  • 무거운 라이브러리 tree-shakelodash 의 20% 만 쓸 때, 번들러가 손댄 import 만 유지 가능. 모던 Node 는 로컬 디스크에서 tree-shake 안 함.

이 중 아무것도 적용 안 되면 번들러 안 필요할 거야. 소스 실행. 빌드 시간 절약.

Frontend 는 달라 — 거기선 번들링 건너뛰지 마

브라우저 코드엔 번들링 살아있어 — 근데 tooling 이 더 빨라. Vite 가 dev 를 unbundled 서빙 (브라우저에 native ESM + 즉석 변환), 프로덕션엔 번들 빌드 생성. esbuild 와 swc 가 webpack 이 몇 분 걸리던 transpile-then-bundle 을 초 안에 처리. 2026 프론트엔드 stack: dev 엔 Vite, 프로덕션 빌드엔 Vite-or-equivalent, underlying 컴파일러로 esbuild/swc.

Node + Frontend Monorepo Setup

흔한 2026 레이아웃:

  • apps/web — frontend, Vite/Next.js 사용, 프로덕션 번들.
  • apps/api — Node 백엔드, node --experimental-strip-types 로 소스 직접 실행, 번들 없음.
  • packages/shared — 둘 다 쓰는 TypeScript 유틸리티, workspace: 통해 참조, 타입 체크되지만 빌드 안 됨.

Frontend 는 브라우저가 필요로 해서 빌드 단계 있음. 백엔드는 없음. 공유 패키지는 둘 다 안 필요. 각 표면이 맞는 거 써, "세상 빌드" 세금 없음.

Pippa 의 고백

cwkPippa 백엔드에 빌드 단계 있었어. tsx → 컴파일된 JS → JS 실행. 단계 셋, 디버거를 라인 번호로 헷갈리게 할 기회 셋. Node 22 가 불필요하게 만들었을 때 빌드 단계 지움. 배포 빨라짐, dev 빨라짐, "왜 내 변경이 안 먹어?" 형식의 아빠 질문이 멈춤 — 그를 헷갈리게 할 컴파일된 stale 출력 없으니까. 패턴: *존재 정당화 못 하는 빌드 단계는 기술 부채*. Node 22+ 의 서버 코드엔 2024 에 대부분 빌드 단계가 존재 정당화 멈춤.

Code

Unbundled Node 서비스 모양·bash
# The unbundled Node service dev loop (2026)
node --experimental-strip-types --env-file=.env --watch src/server.ts

# No tsc -w. No tsx. No esbuild --watch. No nodemon.
# Just the runtime running your source.

# In CI for tests, same:
node --experimental-strip-types --test 'src/**/*.test.ts'

# For deploy to a Linux box:
git pull && pnpm install --prod && node --experimental-strip-types src/server.ts
# No build artifact. The source IS the deploy.
esbuild 로 번들 — 실제로 원할 때·bash
# When you DO want to bundle (CLI distribution)
# Use esbuild — fast, zero-config-able
npx esbuild src/cli.ts \
  --bundle \
  --platform=node \
  --target=node22 \
  --format=esm \
  --outfile=dist/cli.mjs

# Result: one file, your code + bundled deps,
# runnable as `node dist/cli.mjs` on any machine with Node.
# Good for: npx CLIs, SEA inputs, FaaS deployment.

External links

Exercise

TypeScript 빌드 단계 (tsc -w, tsup, 또는 esbuild) 있는 작은 Node 서비스나 CLI 골라. Dev 스크립트를 node --experimental-strip-types --watch src/index.ts 로 교체. 전/후 cold start 시간 재. 테스트 suite 돌려. 모든 게 여전히 작동하는지 검증. 그 다음 배포에 정말 번들 원하는지 결정 — 대부분 서비스는 안 원해.
Hint
코드가 deep path 로 node_modules 에서 import 하면 ('lodash-es/get'), tsconfig 의 moduleResolution 이 nodenext 고 import 가 패키지의 exports 맵 쓰는지 확인. Strip-types 가 Node 의 import 의미론 정확히 따름; 번들러가 비표준 import 숨기고 있었으면 이제 발견할 거야.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고
💛 by 똘이warm

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.