사람들이 “TypeScript 컴파일”이라고 부르는 세 가지
개발자가 TypeScript를 바이너리로 컴파일하는 방법을 검색하면, 보통 한 단어를 공유하지만 서로 매우 다른 세 가지 기법을 마주치게 됩니다:
- 트랜스파일링.
tsc, SWC, esbuild는 TypeScript를 JavaScript로 바꿉니다. 출력물을 실행하려면 여전히 Node.js, Bun, 또는 브라우저가 필요합니다. 바이너리는 전혀 관여하지 않습니다. - 런타임 임베딩.
bun build --compile,deno compile, 그리고 Node.js Single Executable Applications(SEA)는 번들링된 JavaScript를 런타임 전체 사본과 함께 이어붙입니다. 파일은 하나로 합쳐지지만, 엔진이 그 안에 함께 실려 있고 코드는 프로세스가 시작될 때마다 여전히 파싱되고 JIT 컴파일됩니다. - 사전(AOT) 네이티브 컴파일. Perry가 하는 일이 바로 이것입니다. TypeScript는 SWC로 파싱되고, 타입이 해결되고, 제네릭은 모노모픽화되며, LLVM이 머신 코드를 방출합니다. 링커는 평범한 실행 파일을 만들어냅니다 — Rust, Go, C++ 툴체인이 만들어내는 것과 같은 종류의 산출물입니다. 바이너리 안에는 JavaScript 엔진이 전혀 없습니다.
부팅할 엔진도, 시작 시 파싱할 것도 없기 때문에, Perry 바이너리는 약 1밀리초 만에 시작됩니다. 파이프라인 자체는 네이티브 TypeScript 컴파일러 페이지와 컴파일러 내부 구조에서 더 깊이 다룹니다.
바이너리는 얼마나 큰가요?
실제로 사용하는 코드만 컴파일되고 링크되기 때문에, 크기는 무엇을 가져다 쓰는지에 따라 달라집니다:
- hello world는 약 330 KB입니다.
- 일반적인 CLI 도구는 2–5 MB 수준입니다.
- 대형 프레임워크(Fastify, mysql2 등)를 링크하는 완전한 애플리케이션도 약 48 MB 정도입니다.
비교하자면: Node SEA 실행 파일은 node 바이너리 자체의 사본이기 때문에, 코드가 추가되기도 전에 플랫폼에 따라 약 88–118 MB에서 시작합니다. Bun으로 컴파일한 hello world는 Bun 런타임 전체가 내장되어 있어 macOS arm64에서 약 60 MB, Linux x64에서 약 100 MB 정도입니다.
Perry vs bun build --compile vs Node SEA
세 가지 모두 다른 사람에게 건넬 수 있는 단일 파일을 만들어줍니다. 그 외에는 매우 다른 도구들이며, 각각이 누군가에게는 정답이 됩니다:
| Perry | bun build --compile | Node SEA | |
|---|---|---|---|
| 무엇을 만들어내는가 | AOT 컴파일된 머신 코드 (LLVM) | 번들된 JS + 내장된 Bun 런타임 | 번들링된 스크립트가 주입된 node 바이너리의 사본 |
| 실행 모델 | 네이티브 코드, JS 엔진 없음 | 실행 시 JIT (JavaScriptCore) | 실행 시 JIT (V8) |
| Hello-world 크기 | ~330 KB | ~60 MB (macOS arm64)부터 ~100+ MB (Linux/Windows)까지 | ~88–118 MB (node 바이너리 크기) |
| 시작 시간 | ~1 ms | ~10 ms | ~30 ms |
| 크로스 컴파일 | 10개 타겟, Linux에서 Windows/macOS/iOS 빌드 포함 | 가능 — --target으로 Linux, Windows, macOS | 불가능 — 대신 플랫폼별 node 바이너리를 복사 |
| JS/npm 호환성 | 확장 중: axios, zod v4, express, fastify, hono는 네이티브로 컴파일되며, 나머지는 선택적 V8 폴백 지원 | 완전함 — Bun 런타임 그 자체이므로 | 완전한 Node 의미론; 사전 번들링이 필요하며 Node 24 LTS에서는 CommonJS 전용 |
| 상태 | 1.0 이전 | 안정적 | Node 24 LTS 기준 “활발한 개발” 단계의 안정성 |
솔직하게 말하면: 애플리케이션이 npm 생태계 전체에 의존하고 호환성 위험을 전혀 감수하고 싶지 않다면, Bun과 Node SEA는 여러분이 이미 개발 기준으로 삼고 있는 엔진 의미론을 그대로 실행합니다 — 그것이 이들의 강점이며, 배포 환경에 따라 크기 비용은 문제가 되지 않을 수 있습니다. Perry는 다른 거래를 제안합니다. 진정한 사전(AOT) 컴파일, 작은 바이너리, 밀리초 단위의 시작 시간을 얻는 대신, JavaScript 적합성이 V8에서 물려받은 것이 아니라 직접 측정되고 공개되는(test262 기준: v0.5.1146 시점 String 79%, Array 72%) 1.0 이전 컴파일러를 받아들이게 됩니다.
상세 비교: Perry vs Bun과 Perry vs Deno. npm 패키지가 어떻게 컴파일되는지는 실제 npm 패키지와 적합성 스윕을 참고하세요.