THE STATE OF KOTLIN/JS SEBASTIAN AIGNER @TrueSebi Copenhagen - - PowerPoint PPT Presentation

the state of kotlin js sebastian aigner
SMART_READER_LITE
LIVE PREVIEW

THE STATE OF KOTLIN/JS SEBASTIAN AIGNER @TrueSebi Copenhagen - - PowerPoint PPT Presentation

THE STATE OF KOTLIN/JS SEBASTIAN AIGNER @TrueSebi Copenhagen Denmark About me Hi, Im Sebastian! Developer Advocate at JetBrains Focus on Kotlin and Fig. 1: me Education twitter.com/TrueSebi Kotlin & the Web


slide-1
SLIDE 1

Copenhagen Denmark

THE STATE OF KOTLIN/JS SEBASTIAN AIGNER

@TrueSebi

slide-2
SLIDE 2

About me

  • Hi, I‘m Sebastian!
  • Developer Advocate at

JetBrains

  • Focus on Kotlin and

Education

  • Kotlin & the Web
  • Fig. 1: me

twitter.com/TrueSebi github.com/SebastianAigner sebastian.aigner@jetbrains.com

slide-3
SLIDE 3

1. SOME MOTIVATION

Why is Kotlin/JS exciting? Who can benefit the most from K/JS?

slide-4
SLIDE 4

Why Kotlin/JS?

  • Use programming paradigms you’re

familiar with!

  • Prototype quickly!
  • Explore the frontend world!
  • Unlock multiplatform benefits!
slide-5
SLIDE 5

Unlock the power of code sharing!

  • Benefits from multiplatform

development

– Code Sharing – Model Sharing – Knowledge sharing

  • Ecosystem sharing!
slide-6
SLIDE 6

Today’s menu

  • Functionality that is available

now / soon™

  • The next planned steps for the

Kotlin/JS target

  • A long-term-ish outlook
slide-7
SLIDE 7

2. WHERE WE ARE AT

What is currently available and will be available shortly.

slide-8
SLIDE 8

Unified plugin experience

K

  • t

l i n F r

  • n

t e n d P l u g i n kotlin.js Plugin Kotlin/Multiplatform Plugin kotlin2js Plugin Create-React-Kotlin-App IDEA JS

?

slide-9
SLIDE 9

Will be deprecated

Unified plugin experience

Kotlin/Multiplatform Plugin Kotlin Frontend Plugin kotlin.js Plugin kotlin2js Plugin

!

slide-10
SLIDE 10

Moving plugins

From kotlin2js / frontend plugin to kotlin.js

– Same features available – Ever-improving documentation

From kotlin.js plugin to multiplatform

– Minimal changes required – Future-proof DSL for JS target(s) already!

Kotlin/Multiplatform kotlin.js Plugin

slide-11
SLIDE 11

Future-proof DSL

plugins { id("org.jetbrains.kotlin.js") version "1.3.61" } group = "org.example" version = "1.0-SNAPSHOT" repositories { mavenCentral() } dependencies { implementation(kotlin("stdlib-js")) } kotlin { target { browser { testTask { useKarma { useChromeHeadless() } } } } } plugins { kotlin("multiplatform") version "1.3.61" } group = "org.example" version = "1.0-SNAPSHOT" repositories { mavenCentral() } kotlin { js { browser { testTask { useKarma { useChromeHeadless() } } } } sourceSets { val jsMain by getting { dependencies { implementation(kotlin("stdlib-js")) } } val commonMain by getting { dependencies { implementation(kotlin("stdlib-common")) } } val commonTest by getting { dependencies { implementation(kotlin("test-common")) implementation(kotlin("test-annotations-common")) } } } }

slide-12
SLIDE 12

Start your new projects with the kotlin.js plugin

…or do MPP!

slide-13
SLIDE 13

Embracing both worlds?

package.json

>1M!

slide-14
SLIDE 14

Configuring builds

Webpack – without the hassle!

  • Sensible defaults
  • Gradle DSL
  • Full control
  • Fully managed
slide-15
SLIDE 15

Fully managed

No manual environment management necessary

  • Plugin-managed yarn distribution
  • Auto-generated configuration

files

– package.json – webpack.config.js

package.json

slide-16
SLIDE 16

kotlin { target.nodejs() sourceSets.main { dependencies { implementation(kotlin("stdlib-js")) implementation(npm("uuid", "3.3.3")) implementation(npm("chalk")) } } } { "main": "kotlin/playgroundkts.js", "devDependencies": {}, "dependencies": { "kotlin": "1.3.61", "kotlin-test-js-runner": "1.3.61", "kotlin-test": "1.3.61", "uuid": "3.3.3", "chalk": "*" }, "peerDependencies": {}, "optionalDependencies": {}, "bundledDependencies": [], "name": "playgroundkts", "version": "1.0.0-SNAPSHOT" }

package.json build.gradle.kts

slide-17
SLIDE 17

Continuous Gradle Builds

Gradle Task FS watcher Kotlin Compiler Webpack Dev Server Chrome Browser

./gradlew -.continous run

slide-18
SLIDE 18

From IntelliJ IDEA

slide-19
SLIDE 19

Source maps

  • Readable stack traces
  • Browser dev tools superpowers!
slide-20
SLIDE 20

Source maps

slide-21
SLIDE 21

Source maps

slide-22
SLIDE 22

Source maps

slide-23
SLIDE 23

Testing – Test Runners & Browsers

kotlin.target.browser { testTask { useKarma { useIe() useFirefox() useChrome() useChromeHeadless() useOpera() } } }

slide-24
SLIDE 24

Testing – Gradle Test Reports

slide-25
SLIDE 25

Testing – Gradle Test Reports

slide-26
SLIDE 26

Interoperating with the platform

slide-27
SLIDE 27

Browser APIs

  • Generated from W3C standards
  • Statically typed by default, dynamic

as fallback

Official Docs!

slide-28
SLIDE 28

Example using browser API

fun main() { val canvas = document.getElementById("myCanvas") as HTMLCanvasElement val ctx = canvas.getContext("2d") as CanvasRenderingContext2D with(ctx) { repeat(30) { beginPath() fillStyle = listOf("red", "green", "blue").random() rect(randomCoordinate(), randomCoordinate(), 20.0, 20.0) fill() closePath() } } } fun randomCoordinate() = Random.nextDouble(0.0, 200.0)

slide-29
SLIDE 29

Showing off

1 5 8 L i n e s

  • f

K

  • t

l i n / J S !

slide-30
SLIDE 30

A separated browser API

  • Currently: browser API as part of the

standard library

  • In the future: separate artifact,

separate release cycles

… a n d f

  • r

t h e N

  • d

e . j s A P I t

  • !
slide-31
SLIDE 31

Libraries from Gradle

Bring the Kotlin Ecosystem to JS!

kx.serialization Coroutines Ktor Clients . . .

N

  • n

e e d f

  • r

N P M p u b l i s h e d l i b s ! implementation("io.ktor:ktor-client-core:$ktor_version") implementation("io.ktor:ktor-client-js:$ktor_version") implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime-js:0.13.0") plugins { //. . . id("kotlinx-serialization") version "1.3.60" }

slide-32
SLIDE 32

JS Frameworks

Bring the JS ecosystem to Kotlin!

slide-33
SLIDE 33

Packages from NPM

sourceSets.main { dependencies { implementation(npm("react-minimal-pie-chart")) implementation(npm("react-spinkit")) } }

slide-34
SLIDE 34

Bridging the worlds

Dynamic vs static typing

@JsModule("react-spinkit") @JsNonModule external val Spinner: RClass<dynamic> Spinner { attrs.asDynamic().name = spinnerNames.random() attrs.asDynamic().color = colors.random() }

slide-35
SLIDE 35

The proper way

@file:JsModule("react-minimal-pie-chart") @file:JsNonModule import react.RClass import react.RProps external interface PieChartProps: RProps { var data: Array<PiePoint> var lineWidth: Int var paddingAngle: Int var rounded: Boolean var label: Boolean var animate: Boolean var labelStyle: dynamic var labelPosition: Int } @JsName("default") external val PieChart: RClass<PieChartProps> class PiePoint(val title: String, val value: Int, val color: String)

slide-36
SLIDE 36

AMD UMD @JsNonModule @JsModule It can get confusing… import RequireJS

slide-37
SLIDE 37

Standardized type declarations

  • TypeScript declarations for TS

packages

  • d.ts files for JS packages

via DefinitelyTyped

slide-38
SLIDE 38

Automatic declaration generation

  • Convert TypeScript definitions to Kotlin

automatically

  • Gradle integration (same dependency notation!)
  • Currently in experimental stage
  • Expect bugs, give feedback!

P

  • w

e r i n g B r

  • w

s e r & N

  • d

e !

slide-39
SLIDE 39

implementation(npm("left-pad", "1.3.0")) declare function leftPad( str: string|number, len: number, ch?: string|number ): string; declare namespace leftPad { } export = leftPad; //... all external, all @JsModule("left-pad") fun leftPad(str: String, len: Number, ch: String? = definedExternally): String fun leftPad(str: String, len: Number, ch: Number? = definedExternally): String fun leftPad(str: Number, len: Number, ch: String? = definedExternally): String fun leftPad(str: Number, len: Number, ch: Number? = definedExternally): String fun leftPad(str: String, len: Number): String fun leftPad(str: Number, len: Number): String

println(leftPad("Yay Kotlin!", 50))

warning workspace-aggregator > kotlin-js-demo-1.3.50 > left-pad@1.3.0: use String.prototype.padStart()

E v e n w i t h u n i

  • n

t y p e s !

slide-40
SLIDE 40

3. WHERE WE ARE GOING

What changes await Kotlin/JS in the near future.

slide-41
SLIDE 41

Dukat keeps evolving

  • Support for more packages
  • Prioritized by the community
slide-42
SLIDE 42

High level: new IR backend

  • Kotlin Intermediate Representation
  • Future compiler for JS (and other)

targets

  • Will make your life better!
slide-43
SLIDE 43

Expect benefits

slide-44
SLIDE 44

Multi-platform compiler plugins

  • Write platform agnostic plugins
  • Consume platform agnostic plugins
  • Uses reliable public API
slide-45
SLIDE 45

Optimizations

  • More aggressive optimizations
  • Code size

– Dead code eliminiation – No need to ship a full stdlib anymore!

slide-46
SLIDE 46

Some numbers: kotlinx.coroutines w/ IR

Co Code size for example project using coroutines Current Backend IR Backend After Compilation 3.9 MiB 1.1 MiB After JS DCE 713 KiB 430 KiB After Bundle 329 KiB 184 KiB After ZIP 74 KiB 40 KiB IR IR Ba Backend, IR IR DCE, Go Google le Clo losure Comp mpile iler: 116 KiB, , zipped ed 30 KiB

slide-47
SLIDE 47

Incremental compilation

  • Compile at least as fast as with old BE
  • Compile only parts affected by

changes

  • Even faster page-reloads for

continuous builds

slide-48
SLIDE 48

JSDoc & d.ts types generation

  • Expose Kotlin functions, classes as

TypeScript, JSDoc

  • Better tool-support

– Static analyzers – JavaScript IDE suggestions

M

  • r

e f u n i n h y b r i d a p p s !

slide-49
SLIDE 49

@JsExport class TodoItem( val id: Int, val text: String, var completed: Boolean ) { fun complete() { completed = true } }

Kotlin Code

class TodoItem { constructor( id: number, text: string, completed: boolean ) readonly id: number; readonly text: string; completed: boolean; complete(): void }

Derived d.ts

slide-50
SLIDE 50

@JsExport val todoItems = arrayOf<TodoItem>() @JsExport fun finishAll(items: Array<TodoItem>) { items.forEach { it.completed } }

Kotlin Code

const todoItems: Array<todoapp.TodoItem> function finishAll( items: Array<todoapp.TodoItem> ): void

Derived d.ts

slide-51
SLIDE 51

Adapting for IR

slide-52
SLIDE 52

Switching worlds

  • Current backend: open world

– Public declarations available outside module

  • IR backend: closed world
  • Using interop or libraries?

Action may be required!

slide-53
SLIDE 53

On backwards-compatibility

  • Manually export declarations

(@JsExport)

  • No binary compatibility!

– Old BE libraries won’t work with IR – IR libraries won’t work with old BE

slide-54
SLIDE 54

On backwards-compatibility

  • JetBrains libraries receive IR-artifacts
  • Library maintainers: recompile with IR

backend!

  • More details? Come talk to the team!
slide-55
SLIDE 55

When & how to IR

  • Pre-Alpha IR support in 1.3.70
  • Intructions to try

– EAP – Release Blog Post

  • Expect adventures!

T r y i t s

  • n

!

slide-56
SLIDE 56

4. A HOPEFUL OUTLOOK

Interesting topics on the mind of the Kotlin/JS team. No promises!

slide-57
SLIDE 57

ES6 Modules

  • Modern way to export/import

functionality

  • Generating ES6 modules from Kotlin
slide-58
SLIDE 58

Framework support

Challenge: Custom tooling per framework

slide-59
SLIDE 59
slide-60
SLIDE 60

5. WHAT TO DO RIGHT NOW

Getting started, learning more, and giving feedback.

slide-61
SLIDE 61

Kotlin/JS live at KotlinConf

C

  • m

e w i n s t u f f !

slide-62
SLIDE 62

Hands-on learning

S

  • n

!

slide-63
SLIDE 63

A small request: Influence the development!

slide-64
SLIDE 64

THANK YOU AND REMEMBER TO VOTE

Sebastian Aigner @TrueSebi