refactor(build): enable Wasm by default and refactor modules for improved KMP compatibility

Enabled Wasm target across all relevant modules and removed conditional enablement logic. Refactored `core:core-utils` to move JVM-specific code to a new `backend:infrastructure:persistence` module for strict KMP compliance. Updated dependencies, adjusted Gradle configurations, and resolved circular dependencies.
This commit is contained in:
2026-01-09 14:36:10 +01:00
parent 13cfc37b37
commit 35da070893
22 changed files with 513 additions and 526 deletions
+4 -7
View File
@@ -7,7 +7,6 @@ plugins {
kotlin {
// Toolchain is now handled centrally in the root build.gradle.kts
val enableWasm = providers.gradleProperty("enableWasm").orNull == "true"
jvm()
js(IR) {
@@ -15,12 +14,10 @@ kotlin {
// nodejs()
}
// WASM, nur wenn explizit aktiviert
if (enableWasm) {
@OptIn(org.jetbrains.kotlin.gradle.ExperimentalWasmDsl::class)
wasmJs {
browser()
}
// WASM enabled by default
@OptIn(org.jetbrains.kotlin.gradle.ExperimentalWasmDsl::class)
wasmJs {
browser()
}
sourceSets {
+6 -5
View File
@@ -10,7 +10,9 @@ plugins {
kotlin {
// Toolchain is now handled centrally in the root build.gradle.kts
val enableWasm = providers.gradleProperty("enableWasm").orNull == "true"
// Wasm is now a first-class citizen in our stack, so we enable it by default
// val enableWasm = providers.gradleProperty("enableWasm").orNull == "true"
jvm()
js {
@@ -19,10 +21,9 @@ kotlin {
}
}
if (enableWasm) {
@OptIn(org.jetbrains.kotlin.gradle.ExperimentalWasmDsl::class)
wasmJs { browser() }
}
// Always enable Wasm to match the rest of the KMP stack
@OptIn(org.jetbrains.kotlin.gradle.ExperimentalWasmDsl::class)
wasmJs { browser() }
sourceSets {
commonMain.dependencies {
+7 -11
View File
@@ -10,7 +10,6 @@ plugins {
kotlin {
// Toolchain is now handled centrally in the root build.gradle.kts
val enableWasm = providers.gradleProperty("enableWasm").orNull == "true"
jvm()
js {
@@ -19,11 +18,10 @@ kotlin {
}
}
if (enableWasm) {
@OptIn(org.jetbrains.kotlin.gradle.ExperimentalWasmDsl::class)
wasmJs {
browser()
}
// Wasm enabled by default
@OptIn(org.jetbrains.kotlin.gradle.ExperimentalWasmDsl::class)
wasmJs {
browser()
}
sourceSets {
@@ -42,11 +40,9 @@ kotlin {
implementation(libs.sqldelight.driver.web)
}
if (enableWasm) {
val wasmJsMain = getByName("wasmJsMain")
wasmJsMain.dependencies {
implementation(libs.sqldelight.driver.web)
}
val wasmJsMain = getByName("wasmJsMain")
wasmJsMain.dependencies {
implementation(libs.sqldelight.driver.web)
}
commonTest.dependencies {
@@ -6,10 +6,12 @@ import org.w3c.dom.Worker
actual class DatabaseDriverFactory {
actual suspend fun createDriver(): SqlDriver {
// Same as JS, we use a Web Worker for Wasm to support OPFS
val worker = Worker(
js("""new URL("sqlite.worker.js", import.meta.url)""")
)
// In Kotlin/Wasm, we cannot use the js() function inside a function body like in Kotlin/JS.
// We need to use a helper function or a different approach.
// However, for WebWorkerDriver, we need a Worker instance.
// Workaround for Wasm: Use a helper function to create the Worker
val worker = createWorker()
val driver = WebWorkerDriver(worker)
AppDatabase.Schema.create(driver).await()
@@ -17,3 +19,9 @@ actual class DatabaseDriverFactory {
return driver
}
}
// Helper function to create a Worker in Wasm
// Note: Kotlin/Wasm JS interop is stricter.
// We must return a type that Wasm understands as an external JS reference.
// 'Worker' from org.w3c.dom is correct, but we need to ensure the stdlib is available.
private fun createWorker(): Worker = js("new Worker(new URL('sqlite.worker.js', import.meta.url))")
+4 -6
View File
@@ -11,7 +11,6 @@ version = "1.0.0"
kotlin {
// Toolchain is now handled centrally in the root build.gradle.kts
val enableWasm = providers.gradleProperty("enableWasm").orNull == "true"
jvm()
@@ -25,11 +24,10 @@ kotlin {
}
}
if (enableWasm) {
@OptIn(org.jetbrains.kotlin.gradle.ExperimentalWasmDsl::class)
wasmJs {
browser()
}
// Wasm enabled by default
@OptIn(org.jetbrains.kotlin.gradle.ExperimentalWasmDsl::class)
wasmJs {
browser()
}
sourceSets {
+6 -10
View File
@@ -10,7 +10,6 @@ plugins {
kotlin {
// Toolchain is now handled centrally in the root build.gradle.kts
val enableWasm = providers.gradleProperty("enableWasm").orNull == "true"
jvm()
js {
@@ -19,10 +18,9 @@ kotlin {
}
}
if (enableWasm) {
@OptIn(org.jetbrains.kotlin.gradle.ExperimentalWasmDsl::class)
wasmJs { browser() }
}
// Wasm enabled by default
@OptIn(org.jetbrains.kotlin.gradle.ExperimentalWasmDsl::class)
wasmJs { browser() }
sourceSets {
commonMain.dependencies {
@@ -52,11 +50,9 @@ kotlin {
implementation(libs.ktor.client.js)
}
if (enableWasm) {
val wasmJsMain = getByName("wasmJsMain")
wasmJsMain.dependencies {
implementation(libs.ktor.client.js)
}
val wasmJsMain = getByName("wasmJsMain")
wasmJsMain.dependencies {
implementation(libs.ktor.client.js)
}
}
}
@@ -2,28 +2,35 @@ package at.mocode.frontend.core.network
import kotlinx.browser.window
@Suppress("UnsafeCastFromDynamic", "EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING")
@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING")
actual object PlatformConfig {
actual fun resolveApiBaseUrl(): String {
// 1) Prefer a global JS variable (can be injected by index.html or nginx)
val global =
js("typeof globalThis !== 'undefined' ? globalThis : (typeof window !== 'undefined' ? window : (typeof self !== 'undefined' ? self : {}))")
val fromGlobal = try {
(global.API_BASE_URL as? String)?.trim().orEmpty()
} catch (_: dynamic) {
""
}
val fromGlobal = getGlobalApiBaseUrl()
if (fromGlobal.isNotEmpty()) return fromGlobal.removeSuffix("/")
// 2) Try window location origin (same origin gateway/proxy setup)
// In Wasm, we can access a window directly if we are in the browser main thread.
// However, we need to be careful about exceptions.
val origin = try {
window.location.origin
} catch (_: dynamic) {
null
window.location.origin
} catch (e: Throwable) {
null
}
if (!origin.isNullOrBlank()) return origin.removeSuffix("/")
// 3) Fallback to the local gateway
return "http://localhost:8081"
}
}
// Helper function for JS interop in Wasm
// Kotlin/Wasm does not support 'dynamic' type or complex js() blocks inside functions.
// We must use top-level external functions or simple js() expressions.
private fun getGlobalApiBaseUrl(): String = js("""
(function() {
var global = typeof globalThis !== 'undefined' ? globalThis : (typeof window !== 'undefined' ? window : (typeof self !== 'undefined' ? self : {}));
return (global.API_BASE_URL && typeof global.API_BASE_URL === 'string') ? global.API_BASE_URL : "";
})()
""")