Preload Compose Skia WASM chunks to fix serial load waterfall
Deploy website to GitHub Pages / deploy (push) Canceled after 0s

Skiko's Skia-via-WebAssembly runtime is loaded through a dynamic
import() inside webApp.js, so the browser previously only discovered
those multi-MB .wasm files after fully downloading and executing the
JS bundle. Inject <link rel="preload"> hints for the content-hashed
.wasm output into index.html after each browser distribution build so
the WASM fetch starts in parallel with the JS instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-15 15:43:18 +03:00
co-authored by Claude Sonnet 5
parent 29512d153a
commit a0dce39925
+21
View File
@@ -53,6 +53,27 @@ mapOf(
if (src.exists()) {
src.copyRecursively(outputs.files.singleFile.resolve("localization"), overwrite = true)
}
// Compose Multiplatform renders via Skia compiled to WebAssembly (several MB), which is
// loaded through a dynamic import() from inside webApp.js. Without a hint, the browser only
// discovers those .wasm files after it has downloaded, parsed, and started executing the JS
// bundle — a fully serial waterfall. Preloading lets the browser fetch the .wasm in parallel
// with the JS instead. The filenames are content-hashed by webpack, so they're discovered
// here rather than hardcoded in the static index.html source.
val distDir = outputs.files.singleFile
val indexHtml = distDir.resolve("index.html")
if (indexHtml.exists()) {
val wasmFiles = distDir.listFiles { f -> f.extension == "wasm" }.orEmpty().sortedBy { it.name }
if (wasmFiles.isNotEmpty()) {
val preloadLinks = wasmFiles.joinToString("\n") { f ->
""" <link rel="preload" href="${f.name}" as="fetch" type="application/wasm" crossorigin>"""
}
val html = indexHtml.readText()
if ("rel=\"preload\"" !in html) {
indexHtml.writeText(html.replaceFirst("</head>", "$preloadLinks\n</head>"))
}
}
}
}
}
}