9.2 빠른 트랜스파일러 — esbuild, swc, tsx
tsc의 한계와 트랜스파일러의 등장
tsc(TypeScript Compiler)는 타입 체크와 코드 변환을 함께 수행합니다. 대규모 프로젝트에서는 이 방식이 느려질 수 있습니다.
빠른 트랜스파일러는 타입 체크를 건너뛰고 TypeScript → JavaScript 변환만 수행하여 속도를 극적으로 높입니다.
| 도구 | 언어 | 속도 | 타입 체크 |
|---|---|---|---|
tsc | TypeScript | 보통 | ✅ 포함 |
esbuild | Go | 매우 빠름 (100x) | ❌ 없음 |
swc | Rust | 매우 빠름 (70x) | ❌ 없음 |
tsx | (esbuild 기반) | 매우 빠름 | ❌ 없음 |
핵심 원칙: 개발 속도는 트랜스파일러로, 타입 안전성은 별도 tsc 타입 체크로 분리
esbuild
Go 언어로 작성된 초고속 번들러 겸 트랜스파일러입니다.
설치
npm install --save-dev esbuild
기본 사용
# TypeScript → JavaScript 트랜스파일
npx esbuild src/index.ts --outfile=dist/index.js
# 번들링
npx esbuild src/index.ts --bundle --outfile=dist/bundle.js
# 미니파이
npx esbuild src/index.ts --bundle --minify --outfile=dist/bundle.min.js
# 워치 모드
npx esbuild src/index.ts --bundle --watch --outfile=dist/bundle.js
Node.js 서버 빌드
// build.ts
import * as esbuild from 'esbuild';
await esbuild.build({
entryPoints: ['src/index.ts'],
bundle: true,
platform: 'node',
target: 'node20',
format: 'cjs', // 또는 'esm'
outfile: 'dist/index.js',
external: [ // 번들에 포함하지 않을 패키지
'express',
'pg',
/node_modules 전체 제외/
],
sourcemap: true,
});
console.log('Build complete!');
번들 전체 외부화 (Node.js 서버에 유용)
import * as esbuild from 'esbuild';
await esbuild.build({
entryPoints: ['src/index.ts'],
bundle: true,
platform: 'node',
packages: 'external', // node_modules 전체 외부화
outfile: 'dist/index.js',
});
플러그인 활용
import * as esbuild from 'esbuild';
import { TsconfigPathsPlugin } from '@esbuild-plugins/tsconfig-paths';
await esbuild.build({
entryPoints: ['src/index.ts'],
bundle: true,
plugins: [
TsconfigPathsPlugin({ tsconfig: './tsconfig.json' }),
],
outfile: 'dist/index.js',
});
package.json 스크립트
{
"scripts": {
"build": "node build.js",
"build:types": "tsc --emitDeclarationOnly",
"dev": "node --watch dist/index.js",
"typecheck": "tsc --noEmit"
}
}
swc (Speedy Web Compiler)
Rust로 작성된 트랜스파일러로 Babel의 대안입니다. Next.js가 내부적으로 사용합니다.
설치
npm install --save-dev @swc/core @swc/cli
.swcrc 설정
// .swcrc
{
"jsc": {
"parser": {
"syntax": "typescript",
"tsx": true,
"decorators": true
},
"target": "es2022",
"transform": {
"react": {
"runtime": "automatic" // React 17+ JSX transform
}
}
},
"module": {
"type": "commonjs" // 또는 "es6"
},
"sourceMaps": true
}
기본 사용
# 단일 파일 변환
npx swc src/index.ts -o dist/index.js
# 디렉토리 전체 변환
npx swc src -d dist
# 워치 모드
npx swc src -d dist --watch
Jest와 함께 사용 (jest-transform)
npm install --save-dev @swc/jest
// jest.config.js
module.exports = {
transform: {
'^.+\\.(t|j)sx?$': '@swc/jest',
},
};
Babel + ts-jest 대비 테스트 실행 속도가 3~5배 빨라집니다.
NestJS에서 swc 사용
# NestJS CLI에서 swc 빌드
nest build --webpack # 또는
npx @nestjs/cli build --builder swc
// nest-cli.json
{
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"builder": {
"type": "swc",
"options": {
"swcrcPath": ".swcrc"
}
}
}
}
tsx
esbuild 기반의 Node.js용 TypeScript 실행기입니다. ts-node보다 훨씬 빠릅니다.
설치
npm install --save-dev tsx
기본 사용
# TypeScript 파일 직접 실행
npx tsx src/index.ts
# 워치 모드 (파일 변경 시 자동 재시작)
npx tsx watch src/index.ts
# REPL 실행
npx tsx
package.json 스크립트
{
"scripts": {
"dev": "tsx watch src/index.ts",
"start": "node dist/index.js",
"build": "tsc",
"typecheck": "tsc --noEmit"
}
}
ts-node와 비교
# ts-node: 느림 (tsc와 동일한 방식)
npx ts-node src/index.ts
# tsx: 빠름 (esbuild 사용, 타입 체크 없음)
npx tsx src/index.ts
ESM 모드에서 tsx 사용
// package.json
{
"type": "module"
}
# ESM TypeScript 파일 실행
npx tsx src/index.ts # 자동으로 ESM 처리
스크립트 실행 패턴
// scripts/seed-db.ts
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
async function main() {
await prisma.user.createMany({
data: [
{ name: 'Alice', email: 'alice@example.com' },
{ name: 'Bob', email: 'bob@example.com' },
],
});
console.log('Seeded!');
}
main().finally(() => prisma.$disconnect());
{
"scripts": {
"seed": "tsx scripts/seed-db.ts"
}
}
트레이드오프 비교
언제 각 도구를 사용하나?
tsc (순수 타입 체크 전용):
- CI/CD 파이프라인에서 타입 검증
- 라이브러리 배포용 .d.ts 생성
- "typecheck" 스크립트
esbuild (번들 빌드):
- 빠른 프로덕션 빌드
- 서버리스 함수 번들링
- 번들 크기가 중요한 경우
swc (babel 대체):
- Jest 변환 속도 개선
- NestJS 개발 서버
- Babel 플러그인 마이그레이션
tsx (개발 실행):
- Node.js 스크립트 빠른 실행
- 개발 서버 핫 리로드
- 마이그레이션 스크립트 실행
타입 체크 + 빠른 빌드 조합 전략
// package.json — 권장 스크립트 구성
{
"scripts": {
"dev": "tsx watch src/index.ts", // 개발: 빠른 실행
"build": "tsc -p tsconfig.build.json && tsc-alias", // 빌드: 타입 체크 포함
"build:fast": "esbuild src/index.ts --bundle --outfile=dist/index.js", // CI 빠른 빌드
"typecheck": "tsc --noEmit", // 타입 체크만 (별도 CI 스텝)
"test": "vitest" // 테스트: Vite 기반 (esbuild 내장)
}
}
실전 개발 환경 구성
Node.js API 서버 최적 구성
// package.json
{
"scripts": {
"dev": "tsx watch src/index.ts",
"build": "esbuild src/index.ts --bundle --platform=node --packages=external --outfile=dist/index.js --sourcemap",
"start": "node dist/index.js",
"typecheck": "tsc --noEmit"
}
}
개발 흐름:
npm run dev— tsx로 즉시 시작 (타입 체크 없음, 빠름)npm run typecheck— 별도로 타입 오류 확인npm run build— esbuild로 빠른 프로덕션 빌드
CI/CD 파이프라인
# .github/workflows/ci.yml
jobs:
typecheck:
runs-on: ubuntu-latest
steps:
- run: npm run typecheck # 타입 체크
build:
runs-on: ubuntu-latest
steps:
- run: npm run build # 빌드
- run: npm test # 테스트 (swc 기반 jest)
고수 팁
1. Vite는 내부적으로 esbuild를 사용
Vite를 사용하면 별도의 esbuild 설정 없이도 초고속 개발 서버를 이용할 수 있습니다.
2. tsconfig에서 타입 체크와 emit을 분리
// tsconfig.json (타입 체크용)
{ "noEmit": true }
// tsconfig.build.json (빌드용)
{ "extends": "./tsconfig.json", "noEmit": false }
3. 속도 측정
# tsc 빌드 시간 측정
time tsc --noEmit
# esbuild 빌드 시간 측정
time npx esbuild src/index.ts --bundle --outfile=/dev/null
일반적으로 esbuild/swc는 tsc 대비 50~100배 빠릅니다.