본문으로 건너뛰기
Advertisement

9.2 빠른 트랜스파일러 — esbuild, swc, tsx

tsc의 한계와 트랜스파일러의 등장

tsc(TypeScript Compiler)는 타입 체크와 코드 변환을 함께 수행합니다. 대규모 프로젝트에서는 이 방식이 느려질 수 있습니다.

빠른 트랜스파일러는 타입 체크를 건너뛰고 TypeScript → JavaScript 변환만 수행하여 속도를 극적으로 높입니다.

도구언어속도타입 체크
tscTypeScript보통✅ 포함
esbuildGo매우 빠름 (100x)❌ 없음
swcRust매우 빠름 (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"
}
}

개발 흐름:

  1. npm run dev — tsx로 즉시 시작 (타입 체크 없음, 빠름)
  2. npm run typecheck — 별도로 타입 오류 확인
  3. 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배 빠릅니다.

Advertisement