สามสิ่งที่คนเรียกว่า “การคอมไพล์ TypeScript”
เมื่อนักพัฒนาค้นหาวิธีคอมไพล์ TypeScript เป็นไบนารี พวกเขามักจะเจอ เทคนิคที่แตกต่างกันมากสามแบบซึ่งใช้คำเดียวกัน:
- ทรานสไพล์
tsc, SWC และ esbuild แปลง TypeScript เป็น JavaScript เอาต์พุตยังคงต้องมี Node.js, Bun หรือเบราว์เซอร์ในการรัน ไม่มีไบนารีเกี่ยวข้องเลย - การฝังรันไทม์
bun build --compile,deno compileและ Node.js Single Executable Applications (SEA) นำ JavaScript ที่ bundle ของคุณมาต่อรวมกับสำเนาเต็มของรันไทม์ คุณจะได้ไฟล์เดียว แต่ engine ก็ติดมาด้วยข้างในนั้น และโค้ดของคุณก็ยังคงถูก parse และคอมไพล์ แบบ JIT ทุกครั้งที่โพรเซสเริ่มทำงาน - คอมไพล์เนทีฟแบบ Ahead-of-time นี่คือสิ่งที่ Perry ทำ TypeScript ถูก parse ด้วย SWC, resolve type, ทำ monomorphization กับ generic และ LLVM สร้างโค้ดเครื่อง linker ผลิตไฟล์ปฏิบัติการธรรมดา — อาร์ติแฟกต์ประเภทเดียวกับที่ toolchain ของ Rust, Go หรือ C++ ผลิตออกมา ไม่มี JavaScript engine อยู่ในไบนารีเลย
เพราะไม่มี engine ต้อง boot และไม่มีอะไรต้อง parse ตอนเริ่มทำงาน ไบนารีของ Perry จึงเริ่มทำงานในเวลาประมาณหนึ่งมิลลิวินาที ไปป์ไลน์ นี้อธิบายไว้อย่างละเอียดมากขึ้นในหน้า คอมไพเลอร์ TypeScript เนทีฟ และใน โครงสร้างภายในคอมไพเลอร์.
ไบนารีมีขนาดใหญ่แค่ไหน?
ขนาดขึ้นอยู่กับสิ่งที่คุณดึงเข้ามาใช้ เพราะมีเพียงโค้ดที่คุณใช้ จริงเท่านั้นที่ถูกคอมไพล์และ link:
- hello world มีขนาดประมาณ 330 KB
- เครื่องมือ CLI ทั่วไปอยู่ที่ 2–5 MB
- แอปพลิเคชันเต็มรูปแบบที่ link เฟรมเวิร์กขนาดใหญ่ (Fastify, mysql2 และเพื่อน ๆ) มีขนาดประมาณ 48 MB
เพื่อเปรียบเทียบ: ไฟล์ปฏิบัติการ Node SEA คือสำเนาของไบนารี node เอง จึงเริ่มต้นที่ ประมาณ 88–118 MB ขึ้นอยู่กับแพลตฟอร์มก่อนที่จะเพิ่มโค้ดของคุณเข้าไป ส่วน hello world ที่คอมไพล์ด้วย Bun มีขนาดประมาณ 60 MB บน macOS arm64 และประมาณ 100 MB บน Linux x64 เพราะรันไทม์ Bun ทั้งหมดถูก ฝังเข้าไปด้วย
Perry vs bun build --compile vs Node SEA
ทั้งสามตัวให้ไฟล์เดียวที่คุณส่งต่อให้ใครก็ได้ นอกเหนือจากนั้นแล้ว มันเป็นเครื่องมือที่แตกต่างกันมาก และแต่ละตัวก็เป็นคำตอบที่ถูกต้อง สำหรับใครสักคน:
| Perry | bun build --compile | Node SEA | |
|---|---|---|---|
| สิ่งที่ได้ | โค้ดเครื่องที่คอมไพล์แบบ AOT (LLVM) | JS ที่ bundle มา + รันไทม์ Bun ที่ฝังตัว | สำเนาของไบนารี node ที่ฝังสคริปต์ที่ bundle ของคุณเข้าไป |
| โมเดลการรัน | โค้ดเนทีฟ ไม่มี JS engine | 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 เป้าหมาย รวมถึง Windows/macOS/iOS จาก Linux | ได้ — Linux, Windows, macOS ผ่าน --target | ไม่ได้ — ใช้สำเนาไบนารี node ต่อแพลตฟอร์มแทน |
| ความเข้ากันได้กับ JS/npm | กำลังเติบโต: axios, zod v4, express, fastify, hono คอมไพล์ แบบเนทีฟได้แล้ว; ส่วนที่เหลือมี V8 fallback แบบเสริม | เต็มรูปแบบ — เพราะมันคือรันไทม์ Bun เอง | semantics ของ Node เต็มรูปแบบ; ต้อง pre-bundle ก่อน, รองรับเฉพาะ CommonJS บน Node 24 LTS |
| สถานะ | Pre-1.0 | เสถียร | เสถียรภาพระดับ “Active development” ใน Node 24 LTS |
พูดกันตรง ๆ: ถ้าแอปของคุณพึ่งพาระบบนิเวศ npm เต็มรูปแบบและต้องการ ความเสี่ยงด้านความเข้ากันได้เป็นศูนย์ Bun และ Node SEA รัน semantics ของ engine แบบเดียวกับที่คุณพัฒนาอยู่แล้วเป๊ะ ๆ — นั่นคือ จุดแข็งของมัน และต้นทุนด้านขนาดอาจไม่สำคัญสำหรับการ deploy ของคุณ Perry เป็นข้อแลกเปลี่ยนที่ต่างออกไป คุณได้การคอมไพล์แบบ ahead-of-time ที่แท้จริง ไบนารีขนาดเล็ก และเวลาเริ่มต้นระดับ มิลลิวินาที; แลกกับการยอมรับคอมไพเลอร์ pre-1.0 ที่ความสอดคล้องกับ JavaScript ถูกวัดผลและเผยแพร่ (test262: String 79%, Array 72% ณ v0.5.1146) แทนที่จะสืบทอดมาจาก V8
การเปรียบเทียบแบบตัวต่อตัวโดยละเอียด: Perry vs Bun และ Perry vs Deno. สำหรับวิธีที่แพ็กเกจ npm คอมไพล์ ดู npm package จริงคอมไพล์ได้แล้ว: axios, zod, express — กับการกวาด conformance.