From ce2c19f86ce31f646cfdbb6e5af6d78df3e47508 Mon Sep 17 00:00:00 2001 From: Luca Spinazzola Date: Mon, 2 Dec 2024 11:02:48 -0500 Subject: [PATCH] add wasmJs --- gradle/libs.versions.toml | 2 + kotlin-js-store/package-lock.json | 123 +++++++++++++++++- libphonenumber/build.gradle.kts | 19 ++- .../metadata/defaultMetadataLoader.js.kt | 8 ++ .../init/ComposeResourceMetadataLoader.kt | 76 +++++++++++ library-test-resources/build.gradle.kts | 9 +- sample/build.gradle.kts | 7 + .../kotlin/{main.js.kt => main.wasmJs.kt} | 0 sample/src/wasmJsMain/kotlin/main.js.kt | 15 +++ sample/src/wasmJsMain/resources/index.html | 15 +++ sample/src/wasmJsMain/resources/styles.css | 8 ++ 11 files changed, 272 insertions(+), 10 deletions(-) create mode 100644 libphonenumber/src/wasmJsMain/kotlin/io/michaelrocks/libphonenumber/kotlin/metadata/defaultMetadataLoader.js.kt create mode 100644 libphonenumber/src/wasmJsMain/kotlin/io/michaelrocks/libphonenumber/kotlin/metadata/init/ComposeResourceMetadataLoader.kt rename sample/src/jsMain/kotlin/{main.js.kt => main.wasmJs.kt} (100%) create mode 100644 sample/src/wasmJsMain/kotlin/main.js.kt create mode 100644 sample/src/wasmJsMain/resources/index.html create mode 100644 sample/src/wasmJsMain/resources/styles.css diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d79a6410..c55c3056 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -45,6 +45,7 @@ compose-jb = "1.7.1" ## ⬆ = "1.8.0-dev1905" ## ⬆ = "1.8.0-dev1916" ## ⬆ = "1.8.0-dev1920" +kotlinx-browser = "0.3" vanniktech-publish = "0.30.0" okio = "3.9.1" mockative = "3.0.1" @@ -69,3 +70,4 @@ androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "a androidx-runner = { module = "androidx.test:runner", version.ref = "androidx-runner" } co-touchlab-kermit = { module = "co.touchlab:kermit", version.ref = "kermit" } +kotlinx-browser = { module = "org.jetbrains.kotlinx:kotlinx-browser", version.ref = "kotlinx-browser" } diff --git a/kotlin-js-store/package-lock.json b/kotlin-js-store/package-lock.json index 46a371c0..86cc0731 100644 --- a/kotlin-js-store/package-lock.json +++ b/kotlin-js-store/package-lock.json @@ -10,12 +10,20 @@ "workspaces": [ "packages/libphonenumber-kotlin-libphonenumber", "packages/libphonenumber-kotlin-libphonenumber-test", + "packages/libphonenumber-kotlin-libphonenumber-wasm-js", + "packages/libphonenumber-kotlin-libphonenumber-wasm-js-test", "packages/libphonenumber-kotlin-library-test-resources", "packages/libphonenumber-kotlin-library-test-resources-test", + "packages/libphonenumber-kotlin-library-test-resources-wasm-js", + "packages/libphonenumber-kotlin-library-test-resources-wasm-js-test", "packages/libphonenumber-kotlin-sample", "packages/libphonenumber-kotlin-sample-test", + "packages/libphonenumber-kotlin-sample-wasm-js", + "packages/libphonenumber-kotlin-sample-wasm-js-test", "packages_imported/components-resources-js/1.7.1", - "packages_imported/skiko-js/0.8.18" + "packages_imported/skiko-js/0.8.18", + "packages_imported/skiko-wasm-js/0.8.18", + "packages_imported/skiko-js-wasm-runtime/0.8.18" ], "devDependencies": {} }, @@ -2592,6 +2600,14 @@ "resolved": "packages/libphonenumber-kotlin-libphonenumber-test", "link": true }, + "node_modules/libphonenumber-kotlin-libphonenumber-wasm-js": { + "resolved": "packages/libphonenumber-kotlin-libphonenumber-wasm-js", + "link": true + }, + "node_modules/libphonenumber-kotlin-libphonenumber-wasm-js-test": { + "resolved": "packages/libphonenumber-kotlin-libphonenumber-wasm-js-test", + "link": true + }, "node_modules/libphonenumber-kotlin-library-test-resources": { "resolved": "packages/libphonenumber-kotlin-library-test-resources", "link": true @@ -2600,6 +2616,14 @@ "resolved": "packages/libphonenumber-kotlin-library-test-resources-test", "link": true }, + "node_modules/libphonenumber-kotlin-library-test-resources-wasm-js": { + "resolved": "packages/libphonenumber-kotlin-library-test-resources-wasm-js", + "link": true + }, + "node_modules/libphonenumber-kotlin-library-test-resources-wasm-js-test": { + "resolved": "packages/libphonenumber-kotlin-library-test-resources-wasm-js-test", + "link": true + }, "node_modules/libphonenumber-kotlin-sample": { "resolved": "packages/libphonenumber-kotlin-sample", "link": true @@ -2608,6 +2632,14 @@ "resolved": "packages/libphonenumber-kotlin-sample-test", "link": true }, + "node_modules/libphonenumber-kotlin-sample-wasm-js": { + "resolved": "packages/libphonenumber-kotlin-sample-wasm-js", + "link": true + }, + "node_modules/libphonenumber-kotlin-sample-wasm-js-test": { + "resolved": "packages/libphonenumber-kotlin-sample-wasm-js-test", + "link": true + }, "node_modules/loader-runner": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", @@ -3791,6 +3823,14 @@ "resolved": "packages_imported/skiko-js/0.8.18", "link": true }, + "node_modules/skiko-js-wasm-runtime": { + "resolved": "packages_imported/skiko-js-wasm-runtime/0.8.18", + "link": true + }, + "node_modules/skiko-wasm-js": { + "resolved": "packages_imported/skiko-wasm-js/0.8.18", + "link": true + }, "node_modules/socket.io": { "version": "4.8.1", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz", @@ -4950,17 +4990,27 @@ "version": "1.7.1", "devDependencies": {} }, + "packages_imported/skiko-js-wasm-runtime/0.8.18": { + "name": "skiko-js-wasm-runtime", + "version": "0.8.18", + "devDependencies": {} + }, "packages_imported/skiko-js/0.8.18": { "name": "skiko-js", "version": "0.8.18", "devDependencies": {} }, + "packages_imported/skiko-wasm-js/0.8.18": { + "name": "skiko-wasm-js", + "version": "0.8.18", + "devDependencies": {} + }, "packages/libphonenumber-kotlin-libphonenumber": { - "version": "0.1.2-SNAPSHOT", + "version": "0.1.3", "devDependencies": {} }, "packages/libphonenumber-kotlin-libphonenumber-test": { - "version": "0.1.2-SNAPSHOT", + "version": "0.1.3", "devDependencies": { "karma": "6.4.4", "karma-chrome-launcher": "3.2.0", @@ -4976,6 +5026,26 @@ "webpack-cli": "5.1.4" } }, + "packages/libphonenumber-kotlin-libphonenumber-wasm-js": { + "version": "0.1.3", + "devDependencies": {} + }, + "packages/libphonenumber-kotlin-libphonenumber-wasm-js-test": { + "version": "0.1.3", + "devDependencies": { + "karma": "6.4.4", + "karma-chrome-launcher": "3.2.0", + "karma-mocha": "2.0.1", + "karma-sourcemap-loader": "0.4.0", + "karma-webpack": "5.0.1", + "kotlin-web-helpers": "2.0.0", + "mocha": "10.7.3", + "source-map-loader": "5.0.0", + "typescript": "5.5.4", + "webpack": "5.94.0", + "webpack-cli": "5.1.4" + } + }, "packages/libphonenumber-kotlin-library-test-resources": { "version": "0.0.0-unspecified", "devDependencies": {} @@ -4997,6 +5067,26 @@ "webpack-cli": "5.1.4" } }, + "packages/libphonenumber-kotlin-library-test-resources-wasm-js": { + "version": "0.0.0-unspecified", + "devDependencies": {} + }, + "packages/libphonenumber-kotlin-library-test-resources-wasm-js-test": { + "version": "0.0.0-unspecified", + "devDependencies": { + "karma": "6.4.4", + "karma-chrome-launcher": "3.2.0", + "karma-mocha": "2.0.1", + "karma-sourcemap-loader": "0.4.0", + "karma-webpack": "5.0.1", + "kotlin-web-helpers": "2.0.0", + "mocha": "10.7.3", + "source-map-loader": "5.0.0", + "typescript": "5.5.4", + "webpack": "5.94.0", + "webpack-cli": "5.1.4" + } + }, "packages/libphonenumber-kotlin-sample": { "version": "1.0.0-SNAPSHOT", "devDependencies": { @@ -5023,6 +5113,33 @@ "webpack": "5.94.0", "webpack-cli": "5.1.4" } + }, + "packages/libphonenumber-kotlin-sample-wasm-js": { + "version": "1.0.0-SNAPSHOT", + "devDependencies": { + "kotlin-web-helpers": "2.0.0", + "source-map-loader": "5.0.0", + "typescript": "5.5.4", + "webpack": "5.94.0", + "webpack-cli": "5.1.4", + "webpack-dev-server": "4.15.2" + } + }, + "packages/libphonenumber-kotlin-sample-wasm-js-test": { + "version": "1.0.0-SNAPSHOT", + "devDependencies": { + "karma": "6.4.4", + "karma-chrome-launcher": "3.2.0", + "karma-mocha": "2.0.1", + "karma-sourcemap-loader": "0.4.0", + "karma-webpack": "5.0.1", + "kotlin-web-helpers": "2.0.0", + "mocha": "10.7.3", + "source-map-loader": "5.0.0", + "typescript": "5.5.4", + "webpack": "5.94.0", + "webpack-cli": "5.1.4" + } } } } diff --git a/libphonenumber/build.gradle.kts b/libphonenumber/build.gradle.kts index 0039971c..69e87926 100644 --- a/libphonenumber/build.gradle.kts +++ b/libphonenumber/build.gradle.kts @@ -1,4 +1,7 @@ +@file:OptIn(ExperimentalWasmDsl::class) + import com.vanniktech.maven.publish.SonatypeHost +import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl plugins { alias(libs.plugins.org.jetbrains.kotlin.multiplatform) @@ -21,9 +24,12 @@ kotlin { browser() nodejs() } + wasmJs { + browser() + } iosX64();iosArm64();iosSimulatorArm64() macosX64();macosArm64() - applyDefaultHierarchyTemplate() +// applyDefaultHierarchyTemplate() sourceSets { all { languageSettings.optIn("kotlin.ExperimentalStdlibApi") @@ -80,8 +86,17 @@ kotlin { implementation(libs.androidx.runner) } } - val nativeMain by getting { + val nativeMain by creating { + dependsOn(nonJvmMain) + } + val wasmJsMain by getting { dependsOn(nonJvmMain) + dependencies { + implementation(libs.kotlinx.browser) + } + } + val wasmJsTest by getting { + dependsOn(nonJvmTest) } } } diff --git a/libphonenumber/src/wasmJsMain/kotlin/io/michaelrocks/libphonenumber/kotlin/metadata/defaultMetadataLoader.js.kt b/libphonenumber/src/wasmJsMain/kotlin/io/michaelrocks/libphonenumber/kotlin/metadata/defaultMetadataLoader.js.kt new file mode 100644 index 00000000..165dedec --- /dev/null +++ b/libphonenumber/src/wasmJsMain/kotlin/io/michaelrocks/libphonenumber/kotlin/metadata/defaultMetadataLoader.js.kt @@ -0,0 +1,8 @@ +package io.michaelrocks.libphonenumber.kotlin.metadata + +import io.michaelrocks.libphonenumber.kotlin.MetadataLoader +import io.michaelrocks.libphonenumber.kotlin.metadata.init.ComposeResourceMetadataLoader + +actual fun defaultMetadataLoader(): MetadataLoader { + return ComposeResourceMetadataLoader() +} \ No newline at end of file diff --git a/libphonenumber/src/wasmJsMain/kotlin/io/michaelrocks/libphonenumber/kotlin/metadata/init/ComposeResourceMetadataLoader.kt b/libphonenumber/src/wasmJsMain/kotlin/io/michaelrocks/libphonenumber/kotlin/metadata/init/ComposeResourceMetadataLoader.kt new file mode 100644 index 00000000..dc7a664a --- /dev/null +++ b/libphonenumber/src/wasmJsMain/kotlin/io/michaelrocks/libphonenumber/kotlin/metadata/init/ComposeResourceMetadataLoader.kt @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2022 The Libphonenumber Authors + * Copyright (C) 2022 Michael Rozumyanskiy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.michaelrocks.libphonenumber.kotlin.metadata.init + +import co.touchlab.kermit.Logger +import io.github.luca992.libphonenumber_kotlin.libphonenumber.generated.resources.Res +import io.michaelrocks.libphonenumber.kotlin.MetadataLoader +import io.michaelrocks.libphonenumber.kotlin.io.InputStream +import io.michaelrocks.libphonenumber.kotlin.io.OkioInputStream +import okio.Buffer +import org.w3c.xhr.XMLHttpRequest + +/** + * A [MetadataLoader] implementation that reads phone number metadata files as classpath + * resources. + */ + +class ComposeResourceMetadataLoader : MetadataLoader { + + fun fetchFileSynchronously(url: String): ByteArray? { + val xhr = XMLHttpRequest() + xhr.open("GET", url, false) // `false` makes it synchronous + xhr.overrideMimeType("text/plain; charset=x-user-defined") // Interpret response as binary + xhr.send() + + return if (xhr.status == 200.toShort()) { + val responseText = xhr.responseText // Read response as text + // Convert text response to ByteArray + responseText.encodeToByteArray().map { it.toInt() and 0xFF } + ByteArray(responseText.length) { i -> responseText[i].code.toByte() } + } else { + println("Failed to fetch file. Status: ${xhr.status}") + null + } + } + + + override fun loadMetadata(phoneMetadataResource: String): InputStream? { + return try { + val buffer = Buffer() + val path = Res.getUri(phoneMetadataResource) + println("loadMetadata path: $path") + val result = fetchFileSynchronously(path) + return if (result != null) { + buffer.write(result) + OkioInputStream(buffer) + } else { + println("Failed to fetch file.") + null + } + } catch (t: Throwable) { + logger.v("Failed to load metadata from $phoneMetadataResource.path", t) + null + } + } + + companion object { + private val logger = Logger.withTag( + ComposeResourceMetadataLoader::class.simpleName.toString() + ) + } +} diff --git a/library-test-resources/build.gradle.kts b/library-test-resources/build.gradle.kts index e3087c39..03ca2431 100644 --- a/library-test-resources/build.gradle.kts +++ b/library-test-resources/build.gradle.kts @@ -11,11 +11,10 @@ kotlin { browser() nodejs() } -// wasm{ -// browser() -// nodejs() -// d8() -// } + wasmJs { + browser() + nodejs() + } iosX64();iosArm64();iosSimulatorArm64() macosX64();macosArm64() applyDefaultHierarchyTemplate() diff --git a/sample/build.gradle.kts b/sample/build.gradle.kts index 3f00bc83..85a44434 100644 --- a/sample/build.gradle.kts +++ b/sample/build.gradle.kts @@ -1,4 +1,7 @@ +@file:OptIn(ExperimentalWasmDsl::class) + import org.jetbrains.compose.desktop.application.dsl.TargetFormat +import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget plugins { @@ -17,6 +20,10 @@ kotlin { browser() binaries.executable() } + wasmJs { + browser() + binaries.executable() + } fun macosTargets(config: KotlinNativeTarget.() -> Unit) { macosX64(config) macosArm64(config) diff --git a/sample/src/jsMain/kotlin/main.js.kt b/sample/src/jsMain/kotlin/main.wasmJs.kt similarity index 100% rename from sample/src/jsMain/kotlin/main.js.kt rename to sample/src/jsMain/kotlin/main.wasmJs.kt diff --git a/sample/src/wasmJsMain/kotlin/main.js.kt b/sample/src/wasmJsMain/kotlin/main.js.kt new file mode 100644 index 00000000..cbf9e52d --- /dev/null +++ b/sample/src/wasmJsMain/kotlin/main.js.kt @@ -0,0 +1,15 @@ +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.ui.Modifier +import androidx.compose.ui.window.CanvasBasedWindow +import io.luca992.libphonenumber.sample.App + +@OptIn(ExperimentalComposeUiApi::class) +fun main() { + CanvasBasedWindow("libphonenumber-kotlin wasmJs sample") { + Column(modifier = Modifier.fillMaxSize()) { + App("WasmJs Web") + } + } +} diff --git a/sample/src/wasmJsMain/resources/index.html b/sample/src/wasmJsMain/resources/index.html new file mode 100644 index 00000000..e35230aa --- /dev/null +++ b/sample/src/wasmJsMain/resources/index.html @@ -0,0 +1,15 @@ + + + + + libphonenumber sample + + + + +
+ +
+ + + diff --git a/sample/src/wasmJsMain/resources/styles.css b/sample/src/wasmJsMain/resources/styles.css new file mode 100644 index 00000000..e5b3293a --- /dev/null +++ b/sample/src/wasmJsMain/resources/styles.css @@ -0,0 +1,8 @@ +#root { + width: 100%; + height: 100vh; +} + +#root > .compose-web-column > div { + position: relative; +} \ No newline at end of file