feat: add runtime configuration for Caddy-based SPA containerization
Introduced `config.json` runtime configuration fetch mechanism to support the "Build Once, Deploy Everywhere" pattern. Replaced NGINX with Caddy for SPA deployment, enabling SPA routing, security headers, and static asset management. Updated Gradle and Kotlin/JS build configurations to align with the new runtime environment. Enhanced Dockerfile and health checks for optimized CI/CD workflows and improved SPA delivery.
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
import kotlinx.browser.window
|
||||
import kotlinx.coroutines.await
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
@Serializable
|
||||
data class AppConfig(
|
||||
val apiBaseUrl: String
|
||||
)
|
||||
|
||||
suspend fun loadAppConfig(): AppConfig {
|
||||
return try {
|
||||
// Fetch config.json generated by Caddy templates
|
||||
val response = window.fetch("/config.json").await()
|
||||
if (!response.ok) {
|
||||
console.warn("[Config] Failed to load config.json, falling back to defaults")
|
||||
return AppConfig(apiBaseUrl = window.location.origin)
|
||||
}
|
||||
val text = response.text().await()
|
||||
Json.decodeFromString(AppConfig.serializer(), text)
|
||||
} catch (e: dynamic) {
|
||||
console.error("[Config] Error loading config:", e)
|
||||
// Fallback for local development if file is missing
|
||||
AppConfig(apiBaseUrl = "http://localhost:8081")
|
||||
}
|
||||
}
|
||||
@@ -21,20 +21,30 @@ import org.w3c.dom.HTMLElement
|
||||
fun main() {
|
||||
console.log("[WebApp] main() entered")
|
||||
|
||||
// 1. Initialize DI (Koin) with static modules
|
||||
try {
|
||||
startKoin { modules(networkModule, localDbModule, syncModule, pingFeatureModule, authModule, navigationModule) }
|
||||
console.log("[WebApp] Koin initialized with static modules")
|
||||
} catch (e: dynamic) {
|
||||
console.warn("[WebApp] Koin initialization warning:", e)
|
||||
}
|
||||
|
||||
// 2. Async Initialization Chain
|
||||
// We must ensure DB is ready and registered in Koin BEFORE we mount the UI.
|
||||
val provider = GlobalContext.get().get<DatabaseProvider>()
|
||||
|
||||
MainScope().launch {
|
||||
try {
|
||||
// 1. Load Runtime Configuration (Async)
|
||||
console.log("[WebApp] Loading configuration...")
|
||||
val config = loadAppConfig()
|
||||
console.log("[WebApp] Configuration loaded: apiBaseUrl=${config.apiBaseUrl}")
|
||||
|
||||
// 2. Initialize DI (Koin)
|
||||
// We register the config immediately so other modules can use it
|
||||
startKoin {
|
||||
modules(
|
||||
module { single { config } }, // Make AppConfig available for injection
|
||||
networkModule,
|
||||
localDbModule,
|
||||
syncModule,
|
||||
pingFeatureModule,
|
||||
authModule,
|
||||
navigationModule
|
||||
)
|
||||
}
|
||||
console.log("[WebApp] Koin initialized")
|
||||
|
||||
// 3. Initialize Database (Async)
|
||||
val provider = GlobalContext.get().get<DatabaseProvider>()
|
||||
console.log("[WebApp] Initializing Database...")
|
||||
val db = provider.createDatabase()
|
||||
|
||||
@@ -46,12 +56,12 @@ fun main() {
|
||||
)
|
||||
console.log("[WebApp] Local DB created and registered in Koin")
|
||||
|
||||
// 3. Start App only after DB is ready
|
||||
// 4. Start UI
|
||||
startAppWhenDomReady()
|
||||
|
||||
} catch (e: dynamic) {
|
||||
console.error("[WebApp] CRITICAL: Database initialization failed:", e)
|
||||
renderFatalError("Database initialization failed: ${e?.message ?: e}")
|
||||
console.error("[WebApp] CRITICAL: Initialization failed:", e)
|
||||
renderFatalError("Initialization failed: ${e?.message ?: e}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user