TypeScript를 바이너리로 컴파일

명령어 하나로 main.ts가 독립형 네이티브 실행 파일이 됩니다. 대상 머신에 Node.js도 필요 없고, 런타임을 번들링할 필요도 없으며, 사용자를 위한 설치 과정도 없습니다.

terminal

$ perry compile main.ts

✓ Compiled executable: main (2.3 MB)

$ ./main

Hello, World!

사람들이 “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

세 가지 모두 다른 사람에게 건넬 수 있는 단일 파일을 만들어줍니다. 그 외에는 매우 다른 도구들이며, 각각이 누군가에게는 정답이 됩니다:

Perrybun build --compileNode 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 패키지와 적합성 스윕을 참고하세요.

성능 비교

네이티브 컴파일이 비교할 수 없는 효율성을 제공합니다

지표PerryNode.jsBun
바이너리 크기2-5 MB~80 MB~90 MB
시작 시간~1 ms~30 ms~10 ms
런타임 종속성없음Node.jsBun
메모리 오버헤드최소V8 + GCJSC + GC

벤치마크 결과: 최대 18배 빠름

Perry v0.5.279 vs Node.js v25 — RUNS=11 중앙값, Apple M1 Max (낮을수록 좋음)

accumulate
18x
object create
11x
json roundtrip
5.3x
loop overhead
4.5x
math intensive
3.6x
array read
3.3x
fibonacci
3.2x
array write
2.3x
loop data dependent
1.4x
nested loops
1.0x
바이너리 크기낮을수록 좋음
Perry
5 MB
Node.js
80 MB
Bun
90 MB

오늘 바로 첫 바이너리를 컴파일하세요

Homebrew, APT, 또는 winget으로 설치한 다음 perry compile main.ts.