building progressive web apps in kotlin erik hellman
play

BUILDING PROGRESSIVE WEB APPS IN KOTLIN Erik Hellman @ErikHellman - PowerPoint PPT Presentation

BUILDING PROGRESSIVE WEB APPS IN KOTLIN Erik Hellman @ErikHellman Copenhagen Denmark Actual Cross Platform! Types - Theyre pretty great! Type definitions for JavaScript DOM APIs lib.dom.d.ts import { LitElement, html, property,


  1. BUILDING PROGRESSIVE WEB APPS IN KOTLIN Erik Hellman @ErikHellman Copenhagen Denmark

  2. Actual Cross Platform!

  3. Types - They’re pretty great!

  4. Type definitions for JavaScript DOM APIs lib.dom.d.ts

  5. import { LitElement, html, property, customElement } from 'lit-element'; @customElement('simple-greeting') export class SimpleGreeting extends LitElement { @property() name = 'World'; render() { return html`<p>Hello, ${this.name}!*/p>`; } }

  6. class SimpleGreeting : LitElement() { private var name: String = "World" override fun render(): dynamic { return "<p>Hello, $name!*/p>" } companion object { val properties = json("name" to String*:class) } }

  7. JavaScript can be weird... function javaScriptIsWeird(wantNumber) { if (wantNumber) { return 42 } else { return "Here is some text" } }

  8. TypeScript can also be weird! :) function typeScriptExample(wantNumber: boolean): number | string { if (wantNumber) { return 42 } else { return "Here is some text" } }

  9. “It’s complicated…”

  10. Kotlin/JS

  11. Kotlin/JS - build.gradle.kts plugins { id("org.jetbrains.kotlin.js") version "1.3.61" } group = "se.hellsoft" version = "1.0-SNAPSHOT" repositories { mavenCentral() jcenter() } kotlin { target { nodejs() browser() } sourceSets["main"].dependencies { implementation(kotlin("stdlib-js")) } }

  12. Kotlin/JS - Main.kt import kotlin.browser. window val document = window .document fun main() { val button = document .querySelector("#button") *: return button.addEventListener("click", { console .log("Clicked on button!}") } ) }

  13. Kotlin/JS - main.js if (typeof kotlin **= 'undefined') { throw new Error ("Error loading module 'test'. Its dependency 'kotlin' was not found. Please, check whether 'kotlin' is loaded prior to 'test'."); } var test = function (_, Kotlin) { 'use strict'; var Unit = Kotlin.kotlin.Unit; var document; function main$lambda(it) { console .log('Clicked on button!}'); return Unit; } function main() { var tmp$; tmp$ = document.querySelector('#button'); if (tmp$ *= null) { return; } var button = tmp$; button.addEventListener('click', main$lambda); } Object .defineProperty(_, 'document', { get: function () { return document; } }); _.main = main; document = window .document; main(); Kotlin.defineModule('test', _); return _; }(typeof test **= 'undefined' ? {} : test , kotlin);

  14. Kotlin/JS - main.js var main = function (_, Kotlin) { **. function main$lambda(it) { console .log('Clicked on button!}'); return Unit; } function main() { var tmp$; tmp$ = document.querySelector('#button'); if (tmp$ *= null) { return; } var button = tmp$; button.addEventListener('click', main$lambda); } **. main(); **. }(typeof main **= 'undefined' ? {} : main , kotlin);

  15. Progressive Web Apps

  16. Reliable - Fast - Engaging https://developers.google.com/web/progressive-web-apps

  17. Web App Manifest Service Worker manifest.json Web UI

  18. Web App Manifest - manifest.json { "short_name": "Maps", "name": "Google Maps", "icons": [ { "src": "/images/icons-192.png", "type": "image/png", "sizes": "192x192" }, { "src": "/images/icons-512.png", "type": "image/png", "sizes": "512x512" } ], "start_url": "/maps/?source=pwa", "background_color": "#3367D6", "display": "standalone", "scope": "/maps/", "theme_color": "#3367D6" }

  19. Service Worker index.html main.js service-worker.js

  20. Service Worker - index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Kotlin/JS PWA Demo*/title> */head> <body> <div id="appContent">*/div> */body> <script src="main.js">*/script> */html>

  21. Service Worker - main.js if ('serviceWorker' in navigator ) { navigator .serviceWorker .register('/service-worker.js') .then(() *> { console .log('Service Worker registered!') }) .catch(error *> { console .error('Service Worker registration failed!', error) }); }

  22. Service Worker - service-worker.js self .addEventListener('install', event *> { console .log('Service Worker installed!') }); self .addEventListener('activate', event *> { console .log('Service Worker is now active!') }); self .addEventListener('fetch', event *> { const url = new URL (event.request.url); if (url.origin **= location .origin *& url.pathname **= '/dog.svg') { event.respondWith( caches .match('/cat.svg')); } });

  23. Service Worker

  24. Kotlin/JS - Service Workers

  25. Kotlin/JS - Main.kt import kotlin.browser. window fun main() { window .addEventListener("load", { window .navigator.serviceWorker .register("/service-worker.js") .then { console .log("Service worker registered!") } .catch { console .error("Service Worker registration failed: $ it ") } } ) }

  26. Kotlin/JS Output Output Input

  27. Kotlin/JS - Main.kt How can we create this file? import kotlin.browser. window fun main() { window .addEventListener("load", { window .navigator.serviceWorker .register("/service-worker.js") .then { console .log("Service worker registered!") } .catch { console .error("Service Worker registration failed: $ it ") } } ) }

  28. 2 copies of Kotlin/JS stdlib!!! First solution - 2 Gradle modules!

  29. Second solution - use the same script!

  30. Kotlin/JS - Main.kt Same script as we’re currently running in! import kotlin.browser. window fun main() { window.addEventListener("load", { window.navigator.serviceWorker .register("/kotlin-js-pwa.js") .then { console.log("Service worker registered!") } .catch { console.error("Service Worker registration failed: $it") } } ) }

  31. Kotlin/JS - Main.kt Throws ReferenceError in a Service Worker! external val self : ServiceWorkerGlobalScope fun main() { try { window .addEventListener("load", { window .navigator.serviceWorker.register("/kotlin-js-pwa.js") } ) } catch (t: Throwable) { self .addEventListener("install", { event -> console .log("Service Worker installed!") } ) self .addEventListener("activate", { event -> console .log("Service Worker is now active!") } ) } }

  32. Kotlin/JS - Main.kt Reference to Service Worker scope external val self : ServiceWorkerGlobalScope fun main() { try { window .addEventListener("load", { window .navigator.serviceWorker.register("/kotlin-js-pwa.js") } ) } catch (t: Throwable) { self .addEventListener("install", { event -> console .log("Service Worker installed!") } ) self .addEventListener("activate", { event -> console .log("Service Worker is now active!") } ) } }

  33. Implementing the Service Worker

  34. Kotlin/JS - Installing Service Worker const val CACHE_NAME = "my-site-cache-v1" val urlsToCache = arrayOf ( "/", Reference to Service Worker scope "/styles/main.css", "/images/dog.svg", "/images/cat.cvg" ) external val self : ServiceWorkerGlobalScope fun installServiceWorker() { self .addEventListener("install", { event -> event as InstallEvent event.waitUntil( self .caches.open( CACHE_NAME ) .then { it .addAll( urlsToCache ) } ) } }

  35. Kotlin/JS - Implementing offmine cache self .addEventListener("fetch", { event -> event as FetchEvent self .caches.match(event.request) .then { it as Response? return@then it *: self .fetch(event.request) } } )

  36. Calling your HTTP API with Kotlin/JS

  37. Kotlinx.serialization + ktor client plugins { id("org.jetbrains.kotlin.js") version "1.3.61" id("org.jetbrains.kotlin.plugin.serialization") version "1.3.61" } sourceSets["main"].dependencies { implementation(kotlin("stdlib-js")) implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-js:1.3.2") implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime-js:0.14.0") implementation("io.ktor:ktor-client-json-js:1.2.6") implementation("io.ktor:ktor-client-js:1.2.6") }

  38. Kitten API response { "count": 1, "kittens": [ { "name": "Lucy", "age": 3, "gender": "male", "color": "gray", "race": "siberian", "photoUri": "https:*/kitten.io/images/lucy.png" } ] }

  39. Kotlin data classes @Serializable data class KittensResponse( val count: Int, val kittens: List<Kitten> ) @Serializable data class Kitten( val name: String, val age: Int, val gender: Gender, val color: Color, val race: Race, val photoUri: String )

Download Presentation
Download Policy: The content available on the website is offered to you 'AS IS' for your personal information and use only. It cannot be commercialized, licensed, or distributed on other websites without prior consent from the author. To download a presentation, simply click this link. If you encounter any difficulties during the download process, it's possible that the publisher has removed the file from their server.

Recommend


More recommend