From 22cbd6295167336c719d76ab9472d2b85c9ac68d Mon Sep 17 00:00:00 2001 From: Gabriel Souza Date: Fri, 23 Feb 2024 09:01:10 -0300 Subject: [PATCH] WASM support (#289) * Kotlin WASM support * update compose and kodein * Revert kodein build gradle change * Fix detekt * fix build * chore: update compose --- build.gradle.kts | 1 + buildSrc/src/main/kotlin/Setup.kt | 18 ++++++++++++++++++ gradle.properties | 6 +++++- gradle/libs.versions.toml | 10 ++++++---- samples/multiplatform/build.gradle.kts | 14 ++++++++++++++ .../src/wasmJsMain/kotlin/main.wasmJs.kt | 8 ++++++++ .../src/wasmJsMain/resources/index.html | 12 ++++++++++++ .../bottomSheet/internal/Actuals.web.kt} | 0 voyager-core/build.gradle.kts | 3 ++- .../concurrent/AtomicInt32.js.kt | 0 .../concurrent/PlatformDispatcher.js.kt | 0 .../concurrent/ThreadSafeList.js.kt | 0 .../concurrent/ThreadSafeMap.js.kt | 0 .../concurrent/ThreadSafeSet.js.kt | 0 .../lifecycle/ConfigurationChecker.kt | 0 .../NavigatorScreenLifecycleProvider.js.kt | 0 .../lifecycle/Serializable.native.kt | 0 .../platform/KClassEx.js.kt | 0 .../screen/Screen.native.kt | 0 .../screen/ScreenKey.web.kt} | 0 voyager-kodein/build.gradle.kts | 2 +- voyager-koin/build.gradle.kts | 5 ++++- .../voyager/navigator/internal/Actuals.web.kt} | 0 23 files changed, 71 insertions(+), 8 deletions(-) create mode 100644 samples/multiplatform/src/wasmJsMain/kotlin/main.wasmJs.kt create mode 100644 samples/multiplatform/src/wasmJsMain/resources/index.html rename voyager-bottom-sheet-navigator/src/{jsMain/kotlin/cafe/adriel/voyager/navigator/bottomSheet/internal/Actuals.js.kt => commonWebMain/kotlin/cafe/adriel/voyager/navigator/bottomSheet/internal/Actuals.web.kt} (100%) rename voyager-core/src/{jsMain => commonWebMain}/kotlin/cafe.adriel.voyager.core/concurrent/AtomicInt32.js.kt (100%) rename voyager-core/src/{jsMain => commonWebMain}/kotlin/cafe.adriel.voyager.core/concurrent/PlatformDispatcher.js.kt (100%) rename voyager-core/src/{jsMain => commonWebMain}/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeList.js.kt (100%) rename voyager-core/src/{jsMain => commonWebMain}/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeMap.js.kt (100%) rename voyager-core/src/{jsMain => commonWebMain}/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeSet.js.kt (100%) rename voyager-core/src/{jsMain => commonWebMain}/kotlin/cafe.adriel.voyager.core/lifecycle/ConfigurationChecker.kt (100%) rename voyager-core/src/{jsMain => commonWebMain}/kotlin/cafe.adriel.voyager.core/lifecycle/NavigatorScreenLifecycleProvider.js.kt (100%) rename voyager-core/src/{jsMain => commonWebMain}/kotlin/cafe.adriel.voyager.core/lifecycle/Serializable.native.kt (100%) rename voyager-core/src/{jsMain => commonWebMain}/kotlin/cafe.adriel.voyager.core/platform/KClassEx.js.kt (100%) rename voyager-core/src/{jsMain => commonWebMain}/kotlin/cafe.adriel.voyager.core/screen/Screen.native.kt (100%) rename voyager-core/src/{jsMain/kotlin/cafe.adriel.voyager.core/screen/ScreenKey.js.kt => commonWebMain/kotlin/cafe.adriel.voyager.core/screen/ScreenKey.web.kt} (100%) rename voyager-navigator/src/{jsMain/kotlin/cafe.adriel.voyager.navigator.internal/Actuals.js.kt => commonWebMain/kotlin/cafe/adriel/voyager/navigator/internal/Actuals.web.kt} (100%) diff --git a/build.gradle.kts b/build.gradle.kts index 6e5b0bae..a0cc5ca8 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -11,6 +11,7 @@ buildscript { classpath(libs.plugin.ktlint) classpath(libs.plugin.maven) classpath(libs.plugin.multiplatform.compose) + classpath(libs.plugin.atomicfu) } } diff --git a/buildSrc/src/main/kotlin/Setup.kt b/buildSrc/src/main/kotlin/Setup.kt index 29d05185..489061c0 100644 --- a/buildSrc/src/main/kotlin/Setup.kt +++ b/buildSrc/src/main/kotlin/Setup.kt @@ -15,6 +15,7 @@ import org.gradle.kotlin.dsl.withType import org.gradle.kotlin.dsl.getByType import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension +import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl import org.jetbrains.kotlin.gradle.tasks.KotlinCompile private fun BaseExtension.setupAndroid() { @@ -69,6 +70,7 @@ fun Project.setupModuleForAndroidxCompose( fun Project.setupModuleForComposeMultiplatform( withKotlinExplicitMode: Boolean = true, fullyMultiplatform: Boolean = false, + enableWasm: Boolean = true, iosPrefixName: String = "ios" // only used in ios sample ) { plugins.withType { @@ -92,6 +94,10 @@ fun Project.setupModuleForComposeMultiplatform( js(IR) { browser() } + if (enableWasm) { + @OptIn(ExperimentalWasmDsl::class) + wasmJs { browser() } + } macosX64() macosArm64() ios(iosPrefixName) @@ -126,6 +132,13 @@ fun Project.setupModuleForComposeMultiplatform( } if (fullyMultiplatform) { + val commonWebMain by creating { + dependsOn(commonMain) + } + + val jsMain by getting + jsMain.dependsOn(commonWebMain) + val nativeMain by creating { dependsOn(commonMain) } @@ -145,6 +158,11 @@ fun Project.setupModuleForComposeMultiplatform( val iosSimulatorArm64Main = getByName(iosPrefixName + "SimulatorArm64Main").apply { dependsOn(iosMain) } + + if (enableWasm) { + val wasmJsMain by getting + wasmJsMain.dependsOn(commonWebMain) + } } } } diff --git a/gradle.properties b/gradle.properties index 5dcaf4a4..bf523218 100644 --- a/gradle.properties +++ b/gradle.properties @@ -21,8 +21,12 @@ kotlin.native.ignoreIncorrectDependencies=true android.defaults.buildfeatures.buildconfig = false org.jetbrains.compose.experimental.macos.enabled=true -org.jetbrains.compose.experimental.uikit.enabled=true org.jetbrains.compose.experimental.jscanvas.enabled=true +org.jetbrains.compose.experimental.wasm.enabled=true + +kotlinx.atomicfu.enableJvmIrTransformation=true +kotlinx.atomicfu.enableNativeIrTransformation=true +kotlinx.atomicfu.enableJsIrTransformation=true kotlin.mpp.androidSourceSetLayoutVersion=2 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7c708b61..b1847fa8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,12 +2,13 @@ plugin-android = "8.1.1" plugin-ktlint = "11.5.1" plugin-maven = "0.25.3" -plugin-multiplatform-compose = "1.5.11" +plugin-multiplatform-compose = "1.6.0-rc02" plugin-binaryCompatibilityValidator = "0.13.2" +plugin-atomicfu = "0.23.1" -coroutines = "1.7.3" +coroutines = "1.8.0-RC2" kotlin = "1.9.21" -kodein = "7.20.2" +kodein = "7.21.2" koin = "3.4.3" koin-compose = "1.0.4" hilt = "2.49" @@ -24,7 +25,7 @@ rxjava = "3.1.5" junit = "5.10.0" -multiplatformUuid = "0.8.1" +multiplatformUuid = "0.8.2" [libraries] plugin-android = { module = "com.android.tools.build:gradle", version.ref = "plugin-android" } @@ -33,6 +34,7 @@ plugin-ktlint = { module = "org.jlleitschuh.gradle:ktlint-gradle", version.ref = plugin-maven = { module = "com.vanniktech:gradle-maven-publish-plugin", version.ref = "plugin-maven" } plugin-hilt = { module = "com.google.dagger:hilt-android-gradle-plugin", version.ref = "hilt" } plugin-multiplatform-compose = { module = "org.jetbrains.compose:compose-gradle-plugin", version.ref = "plugin-multiplatform-compose" } +plugin-atomicfu = { module = "org.jetbrains.kotlinx:atomicfu-gradle-plugin", version.ref = "plugin-atomicfu" } leakCanary = { module = "com.squareup.leakcanary:leakcanary-android", version.ref = "leakCanary" } coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" } diff --git a/samples/multiplatform/build.gradle.kts b/samples/multiplatform/build.gradle.kts index 32a470e4..5fea4fff 100644 --- a/samples/multiplatform/build.gradle.kts +++ b/samples/multiplatform/build.gradle.kts @@ -3,6 +3,7 @@ import org.jetbrains.compose.desktop.application.dsl.TargetFormat.Dmg import org.jetbrains.compose.desktop.application.dsl.TargetFormat.Msi import org.jetbrains.compose.desktop.application.tasks.AbstractNativeMacApplicationPackageTask import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget +import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl plugins { kotlin("multiplatform") @@ -10,6 +11,19 @@ plugins { id("org.jetbrains.compose") } +kotlin { + @OptIn(ExperimentalWasmDsl::class) + wasmJs { + moduleName = "composeApp" + browser { + commonWebpackConfig { + outputFileName = "composeApp.js" + } + } + binaries.executable() + } +} + setupModuleForComposeMultiplatform( fullyMultiplatform = true, withKotlinExplicitMode = false diff --git a/samples/multiplatform/src/wasmJsMain/kotlin/main.wasmJs.kt b/samples/multiplatform/src/wasmJsMain/kotlin/main.wasmJs.kt new file mode 100644 index 00000000..28aba8e4 --- /dev/null +++ b/samples/multiplatform/src/wasmJsMain/kotlin/main.wasmJs.kt @@ -0,0 +1,8 @@ +import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.ui.window.CanvasBasedWindow +import cafe.adriel.voyager.sample.multiplatform.SampleApplication + +@OptIn(ExperimentalComposeUiApi::class) +fun main() { + CanvasBasedWindow(canvasElementId = "ComposeTarget") { SampleApplication() } +} diff --git a/samples/multiplatform/src/wasmJsMain/resources/index.html b/samples/multiplatform/src/wasmJsMain/resources/index.html new file mode 100644 index 00000000..9ba000fe --- /dev/null +++ b/samples/multiplatform/src/wasmJsMain/resources/index.html @@ -0,0 +1,12 @@ + + + + + Compose App + + + + + + + \ No newline at end of file diff --git a/voyager-bottom-sheet-navigator/src/jsMain/kotlin/cafe/adriel/voyager/navigator/bottomSheet/internal/Actuals.js.kt b/voyager-bottom-sheet-navigator/src/commonWebMain/kotlin/cafe/adriel/voyager/navigator/bottomSheet/internal/Actuals.web.kt similarity index 100% rename from voyager-bottom-sheet-navigator/src/jsMain/kotlin/cafe/adriel/voyager/navigator/bottomSheet/internal/Actuals.js.kt rename to voyager-bottom-sheet-navigator/src/commonWebMain/kotlin/cafe/adriel/voyager/navigator/bottomSheet/internal/Actuals.web.kt diff --git a/voyager-core/build.gradle.kts b/voyager-core/build.gradle.kts index 26570760..c4b8248a 100644 --- a/voyager-core/build.gradle.kts +++ b/voyager-core/build.gradle.kts @@ -3,6 +3,7 @@ plugins { id("com.android.library") id("org.jetbrains.compose") id("com.vanniktech.maven.publish") + id("kotlinx-atomicfu") } setupModuleForComposeMultiplatform(fullyMultiplatform = true) @@ -36,7 +37,7 @@ kotlin { implementation(libs.lifecycle.viewModelCompose) } } - val jsMain by getting { + val commonWebMain by getting { dependencies { implementation(libs.multiplatformUuid) } diff --git a/voyager-core/src/jsMain/kotlin/cafe.adriel.voyager.core/concurrent/AtomicInt32.js.kt b/voyager-core/src/commonWebMain/kotlin/cafe.adriel.voyager.core/concurrent/AtomicInt32.js.kt similarity index 100% rename from voyager-core/src/jsMain/kotlin/cafe.adriel.voyager.core/concurrent/AtomicInt32.js.kt rename to voyager-core/src/commonWebMain/kotlin/cafe.adriel.voyager.core/concurrent/AtomicInt32.js.kt diff --git a/voyager-core/src/jsMain/kotlin/cafe.adriel.voyager.core/concurrent/PlatformDispatcher.js.kt b/voyager-core/src/commonWebMain/kotlin/cafe.adriel.voyager.core/concurrent/PlatformDispatcher.js.kt similarity index 100% rename from voyager-core/src/jsMain/kotlin/cafe.adriel.voyager.core/concurrent/PlatformDispatcher.js.kt rename to voyager-core/src/commonWebMain/kotlin/cafe.adriel.voyager.core/concurrent/PlatformDispatcher.js.kt diff --git a/voyager-core/src/jsMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeList.js.kt b/voyager-core/src/commonWebMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeList.js.kt similarity index 100% rename from voyager-core/src/jsMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeList.js.kt rename to voyager-core/src/commonWebMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeList.js.kt diff --git a/voyager-core/src/jsMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeMap.js.kt b/voyager-core/src/commonWebMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeMap.js.kt similarity index 100% rename from voyager-core/src/jsMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeMap.js.kt rename to voyager-core/src/commonWebMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeMap.js.kt diff --git a/voyager-core/src/jsMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeSet.js.kt b/voyager-core/src/commonWebMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeSet.js.kt similarity index 100% rename from voyager-core/src/jsMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeSet.js.kt rename to voyager-core/src/commonWebMain/kotlin/cafe.adriel.voyager.core/concurrent/ThreadSafeSet.js.kt diff --git a/voyager-core/src/jsMain/kotlin/cafe.adriel.voyager.core/lifecycle/ConfigurationChecker.kt b/voyager-core/src/commonWebMain/kotlin/cafe.adriel.voyager.core/lifecycle/ConfigurationChecker.kt similarity index 100% rename from voyager-core/src/jsMain/kotlin/cafe.adriel.voyager.core/lifecycle/ConfigurationChecker.kt rename to voyager-core/src/commonWebMain/kotlin/cafe.adriel.voyager.core/lifecycle/ConfigurationChecker.kt diff --git a/voyager-core/src/jsMain/kotlin/cafe.adriel.voyager.core/lifecycle/NavigatorScreenLifecycleProvider.js.kt b/voyager-core/src/commonWebMain/kotlin/cafe.adriel.voyager.core/lifecycle/NavigatorScreenLifecycleProvider.js.kt similarity index 100% rename from voyager-core/src/jsMain/kotlin/cafe.adriel.voyager.core/lifecycle/NavigatorScreenLifecycleProvider.js.kt rename to voyager-core/src/commonWebMain/kotlin/cafe.adriel.voyager.core/lifecycle/NavigatorScreenLifecycleProvider.js.kt diff --git a/voyager-core/src/jsMain/kotlin/cafe.adriel.voyager.core/lifecycle/Serializable.native.kt b/voyager-core/src/commonWebMain/kotlin/cafe.adriel.voyager.core/lifecycle/Serializable.native.kt similarity index 100% rename from voyager-core/src/jsMain/kotlin/cafe.adriel.voyager.core/lifecycle/Serializable.native.kt rename to voyager-core/src/commonWebMain/kotlin/cafe.adriel.voyager.core/lifecycle/Serializable.native.kt diff --git a/voyager-core/src/jsMain/kotlin/cafe.adriel.voyager.core/platform/KClassEx.js.kt b/voyager-core/src/commonWebMain/kotlin/cafe.adriel.voyager.core/platform/KClassEx.js.kt similarity index 100% rename from voyager-core/src/jsMain/kotlin/cafe.adriel.voyager.core/platform/KClassEx.js.kt rename to voyager-core/src/commonWebMain/kotlin/cafe.adriel.voyager.core/platform/KClassEx.js.kt diff --git a/voyager-core/src/jsMain/kotlin/cafe.adriel.voyager.core/screen/Screen.native.kt b/voyager-core/src/commonWebMain/kotlin/cafe.adriel.voyager.core/screen/Screen.native.kt similarity index 100% rename from voyager-core/src/jsMain/kotlin/cafe.adriel.voyager.core/screen/Screen.native.kt rename to voyager-core/src/commonWebMain/kotlin/cafe.adriel.voyager.core/screen/Screen.native.kt diff --git a/voyager-core/src/jsMain/kotlin/cafe.adriel.voyager.core/screen/ScreenKey.js.kt b/voyager-core/src/commonWebMain/kotlin/cafe.adriel.voyager.core/screen/ScreenKey.web.kt similarity index 100% rename from voyager-core/src/jsMain/kotlin/cafe.adriel.voyager.core/screen/ScreenKey.js.kt rename to voyager-core/src/commonWebMain/kotlin/cafe.adriel.voyager.core/screen/ScreenKey.web.kt diff --git a/voyager-kodein/build.gradle.kts b/voyager-kodein/build.gradle.kts index 13c4efeb..04e1f0c6 100644 --- a/voyager-kodein/build.gradle.kts +++ b/voyager-kodein/build.gradle.kts @@ -20,7 +20,7 @@ kotlin { api(projects.voyagerNavigator) compileOnly(compose.runtime) compileOnly(compose.runtimeSaveable) - implementation(libs.kodein) + compileOnly(libs.kodein) } } diff --git a/voyager-koin/build.gradle.kts b/voyager-koin/build.gradle.kts index 7e3ad373..1d313ffb 100644 --- a/voyager-koin/build.gradle.kts +++ b/voyager-koin/build.gradle.kts @@ -5,7 +5,10 @@ plugins { id("com.vanniktech.maven.publish") } -setupModuleForComposeMultiplatform(fullyMultiplatform = true) +setupModuleForComposeMultiplatform( + fullyMultiplatform = true, + enableWasm = false // https://github.com/InsertKoinIO/koin/issues/1634 +) android { namespace = "cafe.adriel.voyager.koin" diff --git a/voyager-navigator/src/jsMain/kotlin/cafe.adriel.voyager.navigator.internal/Actuals.js.kt b/voyager-navigator/src/commonWebMain/kotlin/cafe/adriel/voyager/navigator/internal/Actuals.web.kt similarity index 100% rename from voyager-navigator/src/jsMain/kotlin/cafe.adriel.voyager.navigator.internal/Actuals.js.kt rename to voyager-navigator/src/commonWebMain/kotlin/cafe/adriel/voyager/navigator/internal/Actuals.web.kt