Biên dịch TypeScript thành Binary

Một lệnh duy nhất biến main.ts thành một tệp thực thi gốc độc lập. Không cần Node.js trên máy đích, không có runtime đóng gói kèm, không có bước cài đặt nào cho người dùng của bạn.

terminal

$ perry compile main.ts

✓ Compiled executable: main (2.3 MB)

$ ./main

Hello, World!

Ba điều người ta gọi là “biên dịch TypeScript”

Khi các nhà phát triển tìm cách biên dịch TypeScript thành binary, họ thường gặp ba kỹ thuật rất khác nhau nhưng dùng chung một từ:

  • Transpiling. tsc, SWC và esbuild biến TypeScript thành JavaScript. Đầu ra vẫn cần Node.js, Bun hoặc trình duyệt để chạy. Không có binary nào ở đây.
  • Nhúng runtime. bun build --compile, deno compile, và Node.js Single Executable Applications (SEA) nối JavaScript đã đóng gói của bạn với một bản sao đầy đủ của runtime. Bạn có được một tệp duy nhất, nhưng engine vẫn đi kèm bên trong nó và mã của bạn vẫn được parse và biên dịch JIT mỗi lần tiến trình khởi động.
  • Biên dịch gốc ahead-of-time. Đây là những gì Perry làm. TypeScript được parse bằng SWC, kiểu được giải quyết, generic được monomorphize, và LLVM sinh ra mã máy. Linker tạo ra một tệp thực thi bình thường — cùng loại artifact mà toolchain Rust, Go hay C++ tạo ra. Không hề có engine JavaScript nào trong binary.

Vì không có engine nào cần khởi động và không có gì cần parse lúc khởi chạy, một binary Perry khởi động trong khoảng một mili giây. Bản thân pipeline này được mô tả chi tiết hơn trên trang trình biên dịch TypeScript gốc và trong phần cấu trúc bên trong trình biên dịch.

Binary lớn cỡ nào?

Kích thước phụ thuộc vào những gì bạn đưa vào, vì chỉ mã bạn thực sự sử dụng mới được biên dịch và liên kết:

  • Một hello world có kích thước khoảng 330 KB.
  • Các công cụ CLI điển hình rơi vào khoảng 2–5 MB.
  • Ứng dụng đầy đủ liên kết các framework lớn (Fastify, mysql2, và tương tự) có kích thước khoảng 48 MB.

Để so sánh: một tệp thực thi Node SEA chính là một bản sao của binary node, nên nó đã ở khoảng 88–118 MB tùy nền tảng trước cả khi thêm mã của bạn, còn một hello world biên dịch bằng Bun có kích thước khoảng 60 MB trên macOS arm64 và khoảng 100 MB trên Linux x64, vì toàn bộ runtime Bun được nhúng vào.

Perry vs bun build --compile vs Node SEA

Cả ba đều cho bạn một tệp duy nhất có thể đưa cho người khác. Ngoài ra chúng là những công cụ rất khác nhau, và mỗi công cụ là câu trả lời đúng cho một nhu cầu khác nhau:

Perrybun build --compileNode SEA
Nó tạo ra gìMã máy biên dịch AOT (LLVM)JS đóng gói + runtime Bun nhúng kèmBản sao của binary node với script đã đóng gói của bạn được tiêm vào
Mô hình thực thiMã gốc, không có engine JSJIT (JavaScriptCore) lúc runtimeJIT (V8) lúc runtime
Kích thước hello-world~330 KB~60 MB (macOS arm64) đến ~100+ MB (Linux/Windows)~88–118 MB (kích thước của binary node)
Khởi động~1 ms~10 ms~30 ms
Biên dịch chéo10 mục tiêu, bao gồm Windows/macOS/iOS từ LinuxCó — Linux, Windows, macOS qua --targetKhông — thay vào đó sao chép binary node theo từng nền tảng
Khả năng tương thích JS/npmĐang mở rộng: axios, zod v4, express, fastify, hono biên dịch gốc; phần còn lại có tùy chọn V8 dự phòngĐầy đủ — vì đó chính là runtime BunĐầy đủ ngữ nghĩa Node; yêu cầu đóng gói trước, chỉ CommonJS trên Node 24 LTS
Trạng tháiTrước 1.0Ổn địnhĐộ ổn định “Đang phát triển tích cực” trong Node 24 LTS

Nhìn nhận thẳng thắn: nếu ứng dụng của bạn dựa nhiều vào toàn bộ hệ sinh thái npm và bạn muốn rủi ro tương thích bằng không, Bun và Node SEA chạy đúng ngữ nghĩa engine mà bạn đã phát triển theo — đó là thế mạnh của chúng, và cái giá về kích thước có thể không quan trọng với việc triển khai của bạn. Perry là một sự đánh đổi khác. Bạn có được biên dịch ahead-of-time thực sự, binary nhỏ và khởi động tính bằng mili giây; đổi lại bạn chấp nhận một trình biên dịch trước 1.0 mà độ tuân thủ JavaScript được đo lường và công bố (test262: String 79%, Array 72% tính đến v0.5.1146) thay vì được kế thừa từ V8.

So sánh chi tiết: Perry vs Bun Perry vs Deno. Về cách các gói npm biên dịch, xem Các package npm thực tế và một lượt quét conformance.

So sánh hiệu năng

Biên dịch gốc mang lại hiệu quả vượt trội

Chỉ sốPerryNode.jsBun
Kích thước binary2-5 MB~80 MB~90 MB
Thời gian khởi động~1 ms~30 ms~10 ms
Phụ thuộc runtimeKhông cóNode.jsBun
Chi phí bộ nhớTối thiểuV8 + GCJSC + GC

Kết quả benchmark: Nhanh hơn tới 18 lần

Perry v0.5.279 vs Node.js v25 — trung vị RUNS=11, Apple M1 Max (thấp hơn là tốt hơn)

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
Kích thước binaryThấp hơn là tốt hơn
Perry
5 MB
Node.js
80 MB
Bun
90 MB

Biên dịch binary đầu tiên của bạn ngay hôm nay

Cài đặt qua Homebrew, APT hoặc winget — sau đó perry compile main.ts.