Kotlin/JS คือคอมไพเลอร์จาก Kotlin ไปยัง JavaScript ที่ช่วยให้สร้างแอปพลิเคชัน frontend และอินเทอร์เฟซเว็บด้วยภาษา Kotlin ได้ ซึ่งแตกต่างจาก TypeScript, Kotlin/JS ให้การกำหนดชนิดแบบสแตติกที่เข้มงวด การสนับสนุน coroutine และการผสานรวมกับ Kotlin Multiplatform อย่างราบรื่น ตั้งแต่ Kotlin 1.8 เป็นต้นมา คอมไพเลอร์ใช้ backend ที่ใช้ IR เพื่อสร้างโค้ด JavaScript ที่ปรับให้เหมาะสมที่สุด ตามข้อมูลจาก JetBrains, 2025, Kotlin/JS รองรับการผสานรวมกับระบบนิเวศ NPM และ TypeScript ผ่านการสร้างไฟล์ .d.ts อัตโนมัติ
ประเด็นสำคัญ
Kotlin/JS เป็นหนึ่งในสาม backend ของคอมไพเลอร์ Kotlin (ควบคู่กับ JVM และ Native) ที่ออกแบบมาเพื่อแปลงโค้ด Kotlin เป็น JavaScript พัฒนาโดย JetBrains, Kotlin/JS ช่วยให้เขียนแอปพลิเคชันเว็บด้วยภาษาที่มีการกำหนดชนิดแบบสแตติกที่เข้มงวด ในขณะที่ยังคงเข้าถึงระบบนิเวศของไลบรารี JavaScript ผ่านการประกาศภายนอก นับตั้งแต่รุ่นเสถียรแรกใน Kotlin 1.3 คอมไพเลอร์ได้พัฒนาจาก backend ทดลองไปเป็นเครื่องมือที่พร้อมสำหรับการผลิตที่ใช้ในโปรเจกต์อุตสาหกรรม
วัตถุประสงค์หลักของ Kotlin/JS คือ การพัฒนา frontend โดยใช้ Kotlin แทน JavaScript หรือ TypeScript นักพัฒนาได้รับคุณสมบัติทั้งหมดของภาษา Kotlin: null safety, ฟังก์ชันส่วนขยาย, คลาสข้อมูล, coroutine และคลาส sealed โค้ด JavaScript ที่สร้างขึ้นสามารถทำงานในเบราว์เซอร์สมัยใหม่ใดก็ได้หรือในสภาพแวดล้อม Node.js Kotlin/JS มีคุณค่าโดยเฉพาะในโปรเจกต์ Kotlin Multiplatform ที่โมดูลที่ใช้ร่วมกัน (commonMain) พร้อมใช้งานทั้งสำหรับแอปพลิเคชันมือถือและเว็บ
ระบบนิเวศของ Kotlin/JS รวมถึงเฟรมเวิร์กสำหรับสร้างอินเทอร์เฟซผู้ใช้ Compose Multiplatform สำหรับเว็บใช้ Kotlin/JS เป็น backend เป้าหมาย ช่วยให้สร้างคอมโพเนนต์ UI แบบประกาศที่ทำงานในเบราว์เซอร์ได้ โซลูชันทางเลือกอื่นรวมถึงตัวห่อสำหรับ React — Kotlin Wrappers ซึ่งให้ API ที่ปลอดภัยชนิดสำหรับ React, React Router และ Redux
การคอมไพล์ ใน Kotlin/JS ผ่านหลายขั้นตอนการแปลง โค้ด Kotlin ต้นฉบับจะถูกคอมไพล์เป็นการแสดงผลระดับกลาง (IR) ก่อน จากนั้นปรับให้เหมาะสม และสุดท้ายสร้างโค้ด JavaScript ตั้งแต่ Kotlin 1.8 เป็นต้นมา backend เดิม (JsBackend ที่ใช้ AST) ถูกแทนที่ด้วย IR backend อย่างสมบูรณ์ ซึ่งให้การปรับให้เหมาะสมที่ดีกว่า ขนาดโค้ดเอาต์พุตที่เล็กกว่า และความเข้ากันได้กับ TypeScript
ก่อนหน้านี้ Kotlin/JS ใช้ JsBackend ซึ่งทำงานโดยตรงกับ AST (Abstract Syntax Tree) วิธีการนี้มีข้อจำกัด: ความยากลำบากในการสนับสนุนการปรับให้เหมาะสมของแพลตฟอร์ม การขาด IR ที่เป็นหนึ่งเดียวสำหรับ backend ทั้งหมด และไม่สามารถสร้างการประกาศ TypeScript ได้ การเปลี่ยนไปใช้ IR backend แก้ปัญหาเหล่านี้ ทำให้การคอมไพล์เป็นหนึ่งเดียวกันในสาม backend ของ Kotlin และเปิดทางสำหรับการปรับให้เหมาะสมข้าม backend
Kotlin/JS รองรับสองโหมดการสร้างที่กำหนดรูปแบบและการปรับให้เหมาะสมของโค้ดเอาต์พุต โหมดการผลิตใช้ Webpack สำหรับการรวม การย่อ และ tree-shaking โหมดการพัฒนารองรับ Hot Module Replacement สำหรับการพัฒนาแบบวนซ้ำอย่างรวดเร็ว การเลือกโหมดถูกกำหนดค่าใน build.gradle.kts ผ่านการตั้งค่า js.target
kotlin {
js {
browser {
webpackTask {
outputFileName = "app.js"
}
}
binaries.executable()
}
}
การผสานรวม ของ Kotlin/JS กับระบบนิเวศ NPM ดำเนินการผ่าน DSL พิเศษใน build.gradle.kts นักพัฒนาประกาศการพึ่งพา npm ในการตั้งค่า kotlin โดยระบุชื่อแพ็กเกจและเวอร์ชัน Kotlin/JS ดึงแพ็กเกจโดยอัตโนมัติผ่านตัวจัดการแพ็กเกจ npm หรือ yarn เพื่อให้แน่ใจว่าการเข้าถึงไลบรารี JavaScript อย่างปลอดภัยชนิด จึงใช้การประกาศภายนอกที่อธิบายชนิดและฟังก์ชันของไลบรารีให้กับคอมไพเลอร์ Kotlin
การประกาศภายนอก คือการประกาศ Kotlin ที่ทำเครื่องหมายด้วยคีย์เวิร์ด external การประกาศเหล่านี้บอกคอมไพเลอร์ว่าการใช้งานฟังก์ชันหรือคลาสอยู่ในโค้ด JavaScript ไม่ใช่ใน Kotlin JetBrains มีชุดตัวห่อสำเร็จรูปสำหรับไลบรารียอดนิยมเป็นส่วนหนึ่งของ Kotlin Wrappers รวมถึง React, React Router, Redux, Emotion และ MUI สำหรับไลบรารีที่ไม่มีตัวห่อสำเร็จรูป นักพัฒนาสามารถเขียนการประกาศภายนอกด้วยตนเองหรือใช้ตัวสร้างการเชื่อม TypeScript Dukat
kotlin {
js {
browser { }
npm {
dependency("react", "18.3.1")
dependency("react-dom", "18.3.1")
devDependency("webpack", "5.92.0")
}
}
}
// การประกาศภายนอกสำหรับไลบรารี JavaScript
@JsModule("date-fns")
external fun formatDistance(
date: Date, baseDate: Date
): String
TypeScript เป็นส่วนสำคัญของเว็บสมัยใหม่ และ Kotlin/JS รับประกันความเข้ากันได้กับ TypeScript ผ่านการสร้างไฟล์ .d.ts เมื่อตั้งค่า js.generateTsDeclarations = true คอมไพเลอร์จะสร้างการประกาศ TypeScript สำหรับฟังก์ชันและคลาสสาธารณะทั้งหมดของ Kotlin ซึ่งช่วยให้โปรเจกต์ TypeScript นำเข้าโมดูล Kotlin ด้วยการสนับสนุนชนิดอย่างสมบูรณ์ การสร้างการประกาศ TypeScript ทำงานเฉพาะกับ IR backend และเป็นหนึ่งในเหตุผลหลักในการย้ายจาก backend เดิม
IR Backend (Intermediate Representation) เป็น backend แบบรวมสำหรับสามแพลตฟอร์ม Kotlin: JVM, JS และ Native โดยใช้การแสดงผลระดับกลางร่วมกันที่ผ่านหลายขั้นตอนการปรับให้เหมาะสมก่อนสร้างโค้ดเป้าหมาย สำหรับ Kotlin/JS, IR backend กลายเป็นข้อบังคับตั้งแต่ Kotlin 1.8.0 แทนที่ backend เดิมที่ใช้ AST ซึ่งถูกทำเครื่องหมายว่าล้าสมัย
ข้อดีของ IR backend สำหรับ Kotlin/JS รวมถึง การปรับให้เหมาะสมของโค้ดที่ดีขึ้น ในระดับ IR การลดขนาด bundle ผ่านการกำจัดโค้ดที่ตายแล้วและการปรับให้เหมาะสมแบบ inline รวมถึงการสนับสนุนการประกาศ TypeScript IR backend ยังรับประกันการจัดการที่ถูกต้องของฟังก์ชัน inline, เจเนอริก reified และฟังก์ชัน suspend เมื่อแปลเป็น JavaScript ซึ่งเป็นปัญหาก่อนหน้านี้ใน backend เดิม
| คุณสมบัติ | Backend เดิม (AST) | IR Backend |
|---|---|---|
| การประกาศ TypeScript | ไม่รองรับ | สร้างอัตโนมัติ |
| การกำจัดโค้ดที่ตายแล้ว | จำกัด | สมบูรณ์ ในระดับ IR |
| ฟังก์ชัน inline | ปัญหาความถูกต้อง | การจัดการที่ถูกต้อง |
| เจเนอริก reified | ไม่รองรับ | รองรับ |
| ขนาด Bundle | พื้นฐาน | เล็กลง 20–30% |
โปรเจกต์ Kotlin/JS ที่สมบูรณ์เริ่มต้นด้วยการตั้งค่า build.gradle.kts ปลั๊กอิน kotlin multiplatform ช่วยให้ตั้งค่า Kotlin/JS เป็นหนึ่งในแพลตฟอร์มเป้าหมายได้ มาดูตัวอย่างการตั้งค่าสำหรับแอปพลิเคชันเว็บกับ React
plugins {
kotlin("multiplatform") version "2.0.21"
id("org.jetbrains.kotlin-wrappers") version "1.0.0-pre.775"
}
kotlin {
js {
browser { }
binaries.executable()
generateTsDeclarations = true
}
}
dependencies {
implementation(enwraps(react, reactDom))
}
หลังจากการตั้งค่า สามารถเขียนคอมโพเนนต์ React ใน Kotlin ได้ Kotlin Wrappers ให้ API ที่ปลอดภัยชนิดสำหรับ React รวมถึงคอมโพเนนต์เชิงฟังก์ชัน, hooks และไวยากรณ์คล้าย JSX ผ่าน ตัวสร้าง DSL ตัวอย่างคอมโพเนนต์ Counter แสดงการทำงานกับ useState และตัวจัดการเหตุการณ์
@OptIn(ExperimentalWrapperApi::class)
val Counter = FC<Props> {
var count = useState(0)
div {
+"Counter value: ${count.component1()}"
button {
onClick = { count.component2()(count.component1() + 1) }
+"Increment"
}
}
}
fun main() {
createRoot(document.getElementById("root")!!).render(
createElement(Counter)
)
}
การสร้างโปรเจกต์ Kotlin/JS ดำเนินการผ่านงาน Gradle jsDevelopmentRun เริ่มเซิร์ฟเวอร์พัฒนา Webpack ด้วย HMR สำหรับการพัฒนา jsProductionExecutableCompileSync สร้าง bundle การผลิตที่มีการย่อและ tree-shaking ไฟล์ HTML สุดท้ายที่รวม JavaScript ที่คอมไพล์แล้วถูกสร้างโดยปลั๊กอิน webpack และวางใน build/dist
// เริ่มเซิร์ฟเวอร์พัฒนาด้วย HMR
./gradlew jsDevelopmentRun
// การสร้างสำหรับการผลิตพร้อมการย่อ
./gradlew jsProductionExecutableCompileSync
// เอาต์พุตใน build/dist/productionExecutable/
TypeScript เป็นคู่แข่งหลักของ Kotlin/JS ในด้าน JavaScript ที่มีการกำหนดชนิด ภาษาทั้งสองคอมไพล์เป็น JavaScript และเพิ่มการกำหนดชนิดแบบสแตติกเหนือ JS แบบไดนามิก อย่างไรก็ตาม Kotlin/JS มีข้อดีหลายประการ: null safety เป็นค่าเริ่มต้น, คลาส sealed, coroutine และการผสานรวมกับ Kotlin Multiplatform อย่างราบรื่น ในขณะที่ TypeScript มีชุมชนที่ใหญ่กว่า ไลบรารีสำเร็จรูปที่มีชนิดมากกว่า และระบบนิเวศที่เติบโตเต็มที่กว่า
ประสิทธิภาพการพัฒนาด้วย Kotlin/JS อาจสูงกว่าสำหรับทีมที่ใช้ Kotlin อยู่แล้วในส่วนอื่นของโปรเจกต์ เนื่องจากไม่ต้องสลับภาษา TypeScript ยังคงเป็นตัวเลือกที่ได้รับความนิยมมากกว่าสำหรับโปรเจกต์เว็บบริสุทธิ์ที่ไม่ได้ใช้ Kotlin Multiplatform อย่างไรก็ตาม ด้วยความนิยมที่เพิ่มขึ้นของ Compose Multiplatform สำหรับเว็บ Kotlin/JS กำลังได้รับตำแหน่งเป็นทางเลือกแทน React และ Angular
| คุณสมบัติ | Kotlin/JS | TypeScript |
|---|---|---|
| Null safety | เป็นค่าเริ่มต้น | strictNullChecks เป็นตัวเลือก |
| คลาส sealed | รองรับ | ผ่าน union types |
| Coroutine | โดยธรรมชาติ | ผ่าน async/await |
| การผสานรวม KMM | เต็มรูปแบบ | ไม่มี |
| ขนาดชุมชน | เล็ก | ใหญ่มาก |
| ชนิดสำเร็จรูปสำหรับไลบรารี | จำกัด (DefinitelyTyped ผ่าน Dukat) | DefinitelyTyped (ไลบรารีนับพัน) |
การเลือกระหว่าง Kotlin/JS และ TypeScript ขึ้นอยู่กับบริบทของโปรเจกต์ หากทีมใช้ Kotlin Multiplatform อยู่แล้วหรือวางแผนจะเริ่มใช้ Kotlin/JS เป็นตัวเลือกที่สมเหตุสมผลสำหรับส่วน frontend สำหรับโปรเจกต์เว็บแบบแยกเดี่ยว TypeScript ยังคงเป็นโซลูชันที่ใช้งานได้จริงมากกว่า เนื่องจากความพร้อมของชนิดสำเร็จรูปสำหรับไลบรารี JavaScript และจำนวนนักพัฒนาที่มากขึ้นในตลาด
คำถามที่พบบ่อย
ได้ JetBrains มี Kotlin Wrappers — ตัวห่อ Kotlin ที่ปลอดภัยชนิดสำหรับ React, React Router และ Redux ซึ่งช่วยให้เขียนคอมโพเนนต์ React ใน Kotlin ด้วยการสนับสนุน hooks และ DSL คล้าย JSX อย่างสมบูรณ์
เมื่อเปิด generateTsDeclarations = true Kotlin/JS จะสร้างไฟล์ .d.ts สำหรับ API สาธารณะทั้งหมด โปรเจกต์ TypeScript สามารถนำเข้าโมดูล Kotlin ด้วยชนิดที่สมบูรณ์เหมือนแพ็กเกจ npm ทั่วไป
ขนาด bundle ขึ้นอยู่กับไลบรารีที่ใช้ แอปพลิเคชัน Hello World ขั้นต่ำใช้ประมาณ 300 KB รวม Kotlin stdlib ด้วย React และ Kotlin Wrappers ขนาดเพิ่มขึ้นเป็น 400–600 KB
ได้ Kotlin/JS สามารถใช้พัฒนา ฟังก์ชัน serverless และยูทิลิตี้คอนโซลภายใต้ Node.js โดยระบุ js.nodejs แทน js.browser ในการตั้งค่า
Kotlin/Wasm เป็น backend ทดลองสำหรับ WebAssembly ในขณะที่ Kotlin/JS สร้างโค้ด JavaScript Wasm ให้ประสิทธิภาพสูงกว่าแต่มีการเข้าถึง DOM ของเบราว์เซอร์อย่างจำกัด
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ