ข้ามไปยังเนื้อหา

การเลือกภาษา

ทุก Wasm Toolchain มีจุดหมายปลายทางเดียวกัน — ไฟล์ .wasm Binary ที่รันใน browser — แต่แต่ละตัวเดินบนเส้นทางที่ต่างกัน การเลือกที่ถูกต้องขึ้นอยู่กับ Codebase ที่มีอยู่, ทักษะของทีม และข้อจำกัดของโปรเจกต์

คำถามRustC / EmscriptenAssemblyScriptTinyGo
ทีมเขียนภาษานี้อยู่แล้วหรือ?บางทีบางทีถ้ารู้จัก TSถ้ารู้จัก Go
มี Codebase ที่ต้อง Port หรือ?ไม่ใช่ไม่ไม่
ขนาด Binary เป็นหลัก?ยอดเยี่ยมใหญ่ (libc overhead)ยอดเยี่ยมดี
GC / Runtime Overhead?ไม่มีเฉพาะ libcไม่มีน้อยมาก
JS Interop ที่สมบูรณ์ (String, Object)?ใช่ (wasm-bindgen)ผ่าน ccall/cwrapผ่าน Loaderจำกัด
ครอบคลุม Standard Library?ครบถ้วนครบถ้วน libcจำกัดบางส่วน
รองรับ Async / Concurrency?ผ่าน Futuresผ่าน Asyncifyจำกัดจำกัด
Learning Curve (เฉพาะ Wasm)?ปานกลางต่ำ (ถ้ารู้ C)ต่ำมาก (TS)ต่ำ (ถ้ารู้ Go)

เลือก Rust เมื่อคุณ เขียนโค้ด Wasm ใหม่ และต้องการ:

  • Binary ที่เล็กที่สุดเท่าที่เป็นไปได้ (ไม่มี GC, ไม่มี Runtime Heap)
  • JS Binding ที่ปลอดภัยและอัตโนมัติผ่าน wasm-bindgen
  • Crate Ecosystem ที่ออกแบบมาสำหรับ wasm32-unknown-unknown
  • แพ็กเกจ npm ที่ Publish ได้จาก wasm-pack
Terminal window
wasm-pack build --target web
# → pkg/ พร้อม npm publish

เลือก Emscripten เมื่อคุณ Port ไลบรารี C/C++ ที่มีอยู่ และต้องการ:

  • printf, malloc, File I/O และ POSIX API ทำงานได้โดยไม่แก้โค้ด
  • OpenGL Emulation ผ่าน WebGL (-sUSE_WEBGL2)
  • Build ขั้นตอนเดียวจาก Makefile หรือ CMake Project ที่มีอยู่
Terminal window
emcc existing_lib.c -o out.js -sEXPORTED_FUNCTIONS='["_my_api"]' -O2

เลือก AssemblyScript เมื่อทีมของคุณ เขียน TypeScript และต้องการ:

  • Learning Curve ที่ต่ำมาก (Syntax เดิม แค่ Numeric Type ต่างกัน)
  • Wasm Module เล็กและ Self-contained โดยไม่มี Dependency
  • วน Iteration เร็วโดยไม่ต้องตั้งค่า Rust หรือ C Toolchain
Terminal window
npx asc assembly/index.ts --outFile build/release.wasm --optimize

เลือก TinyGo เมื่อทีมของคุณ เขียน Go และต้องการแชร์แพ็กเกจ Pure Logic ระหว่าง Go Backend กับ Browser Frontend:

Terminal window
tinygo build -o wasm.wasm -target wasm ./main.go

หมายเหตุ: TinyGo ไม่รองรับ Go Standard Library ทั้งหมด แพ็กเกจที่ใช้ net, os หรือ Reflection อาจคอมไพล์ไม่ได้ ตรวจสอบ ตาราง Package Support ของ TinyGo ก่อนตัดสินใจ

  1. มีโค้ด C/C++ ที่ทำงานได้อยู่แล้วหรือ? → Emscripten
  2. ทีมเขียน TypeScript และต้องการเริ่มต้นเร็ว? → AssemblyScript
  3. ทีมเขียน Go หรือ? → TinyGo
  4. เขียนโค้ดใหม่และต้องการขนาด Binary ที่ดีที่สุดพร้อม JS Interop? → Rust
ตัวเลือกBenefitCost
Rust + wasm-bindgenMemory Safety จาก Ownership Model และ Binary Size เล็กมาก ไม่มี GCLearning Curve สูงกว่าตัวอื่นเพราะต้องเข้าใจ Ownership/Borrowing
C/C++ + EmscriptenEcosystem C/C++ มหาศาล Port Codebase เดิมได้เกือบทันทีGlue Code และ POSIX Emulation Layer เพิ่ม Runtime Overhead ทำให้ Binary ใหญ่
AssemblyScriptSyntax คุ้นเคยสำหรับทีม TypeScript เริ่มต้นได้เร็วที่สุดEcosystem จำกัดมาก และ ไม่ semantically เหมือน TypeScript ทุกจุด — Type System ต่างกัน
  • เลือกภาษาตามความถนัดของทีมอย่างเดียวโดยไม่ดู Binary Size ที่ตามมา เช่น ใช้ Emscripten สำหรับ Module เล็กๆ ที่ไม่มี Codebase เดิมให้ Port ทำให้ Ship Runtime ใหญ่เกินจำเป็น
  • Ship Emscripten Build แบบไม่ Optimise — ไม่ Strip POSIX Emulation Layer และไม่ใช้ Flag อย่าง -O3 หรือ -sMINIMAL_RUNTIME จน Bundle บวม
  • คิดว่า AssemblyScript คือ TypeScript ทั้งหมด แล้วใช้ Syntax หรือ Semantics ที่ asc ไม่รองรับ จนเจอ Compile Error หรือ Bug แปลกๆ ที่ตามหายาก

💡 ตัวอย่างจากของจริง

Figma เลือก C++ กับ Emscripten สำหรับ Rendering Engine ที่ Port มาจาก Desktop ส่วน 1Password ใช้ Rust คอมไพล์เป็น Wasm สำหรับ Core Cryptography และ Vault Logic ที่รันใน browser ขณะที่ Shopify Functions ให้ Merchant เขียน Custom Checkout Logic ด้วย Rust หรือ AssemblyScript แล้วคอมไพล์เป็น Wasm — สามตัวอย่างที่เลือกภาษาต่างกันตาม Requirement ของตัวเอง

Toolchain ใดเหมาะที่สุดเมื่อต้อง Port ไลบรารี C ที่มีอยู่ซึ่งใช้ printf และ malloc?
Toolchain สองตัวใดที่ผลิต Wasm Binary ขนาดเล็กที่สุดเพราะไม่มี Garbage Collector หรือ Runtime Heap?
ข้อจำกัดหลักของ TinyGo เมื่อคอมไพล์โค้ด Go ไปยัง Wasm คืออะไร?
คำสั่งใด Publish โปรเจกต์ Rust Wasm เป็นแพ็กเกจ npm?