Summon 0.5.2.1 introduces comprehensive WebAssembly support, bringing near-native performance to web applications while maintaining full compatibility with server-side rendering and JavaScript fallbacks.
WebAssembly (WASM) is a binary instruction format that runs at near-native performance in web browsers. Summon's WASM implementation provides:
Create a new WASM project:
# Download Summon CLI from GitHub Packages
# Visit: https://github.com/codeyousef/summon/packages
# Or use the native executable directly
# Create a new project (start from the standalone template)
java -jar summon-cli-0.5.2.1.jar init my-wasm-app --mode=standalone
# Navigate to project
cd my-wasm-app
# Run development server (after enabling the WASM target)
./gradlew wasmJsBrowserDevelopmentRun
// src/wasmJsMain/kotlin/App.kt
import code.yousef.summon.annotation.Composable
import code.yousef.summon.components.display.Text
import code.yousef.summon.components.input.Button
import code.yousef.summon.components.layout.Column
import code.yousef.summon.modifier.Modifier
import code.yousef.summon.state.mutableStateOf
import code.yousef.summon.runtime.remember
@Composable
fun App() {
val count = remember { mutableStateOf(0) }
Column(modifier = Modifier()) {
Text(
text = "WASM Counter: ${count.value}",
modifier = Modifier()
)
Button(
onClick = { count.value++ },
label = "Increment (+1)",
modifier = Modifier()
)
Button(
onClick = { count.value += 10 },
label = "Fast Increment (+10)",
modifier = Modifier()
)
}
}
// build.gradle.kts
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
kotlin("multiplatform")
kotlin("plugin.serialization")
}
kotlin {
wasmJs {
moduleName = "my-wasm-app"
browser {
commonWebpackConfig {
outputFileName = "my-wasm-app.js"
devServer = devServer?.copy(
port = 3000,
open = false
)
}
}
binaries.executable()
}
// JVM target for SSR
jvm {
compilations.all {
compileTaskProvider.configure {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_17)
}
}
}
}
sourceSets {
val commonMain by getting {
dependencies {
// New group ID (preferred)
implementation("codes.yousef:summon:0.5.2.1")
// Legacy (deprecated; supported only until 0.5.2.1)
// implementation("io.github.codeyousef:summon:0.5.2.1")
}
}
val wasmJsMain by getting {
dependencies {
// New group ID (preferred)
implementation("codes.yousef:summon-wasm-js:0.5.2.1")
// Legacy (deprecated; supported only until 0.5.2.1)
// implementation("io.github.codeyousef:summon-wasm-js:0.5.2.1")
}
}
val jvmMain by getting {
dependencies {
// New group ID (preferred)
implementation("codes.yousef:summon-jvm:0.5.2.1")
// Legacy (deprecated; supported only until 0.5.2.1)
// implementation("io.github.codeyousef:summon-jvm:0.5.2.1")
}
}
}
}
// src/wasmJsMain/kotlin/Main.kt
import code.yousef.summon.runtime.wasmMain
fun main() {
wasmMain {
App()
}
}
<!-- src/wasmJsMain/resources/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My WASM App</title>
<style>
body {
margin: 0;
padding: 20px;
font-family: system-ui;
}
#loading {
text-align: center;
padding: 50px;
}
</style>
</head>
<body>
<div id="root">
<div id="loading">Loading WASM application...</div>
</div>
<script>
// Progressive loading with fallback
async function loadApp() {
try {
if ('WebAssembly' in window) {
console.log('Loading WASM version...');
await import('./my-wasm-app.js');
} else {
console.log('WASM not supported, loading JS fallback...');
await import('./my-app-js-fallback.js');
}
} catch (error) {
console.error('Failed to load application:', error);
document.getElementById('loading').innerHTML =
'Failed to load application. Please refresh the page.';
}
}
loadApp();
</script>
</body>
</html>
# Development build with source maps
./gradlew wasmJsBrowserDevelopmentRun
# Production build optimized
./gradlew wasmJsBrowserProductionWebpack
# Run tests
./gradlew wasmJsTest
# Clean build
./gradlew clean wasmJsBrowserDistribution
# Start development server with hot reload
./gradlew wasmJsBrowserDevelopmentRun --continuous
Enable source maps for debugging:
// build.gradle.kts
kotlin {
wasmJs {
browser {
commonWebpackConfig {
devtool = "source-map"
mode = "development"
}
}
}
}
// build.gradle.kts - Production optimizations
kotlin {
wasmJs {
browser {
commonWebpackConfig {
mode = "production"
optimization {
minimize = true
splitChunks {
chunks = "all"
}
}
}
}
}
}
// Lazy loading for large components
@Composable
fun App() {
var showHeavyComponent by remember { mutableStateOf(false) }
Column(modifier = Modifier()) {
Button(
onClick = { showHeavyComponent = true },
label = "Load Heavy Component",
modifier = Modifier()
)
if (showHeavyComponent) {
// This component will be lazy-loaded
HeavyDataVisualizationComponent()
}
}
}
// Use remember for expensive computations
@Composable
fun ExpensiveComponent(data: List<DataPoint>) {
val processedData = remember(data) {
// Expensive computation cached until data changes
data.map { processComplexCalculation(it) }
}
DataVisualization(data = processedData)
}
Summon automatically detects WASM support and falls back gracefully:
// Browser compatibility is handled automatically
// Your code works the same across all targets
@Composable
fun UniversalComponent() {
val platform = remember { detectPlatform() }
Column(modifier = Modifier()) {
Text("Running on: $platform", modifier = Modifier())
// Component works on WASM, JS, and JVM
}
}
| Browser | WASM Support | Performance | Notes | |---------------|--------------|-------------|----------------------| | Chrome 69+ | ✅ Full | Excellent | Best performance | | Firefox 62+ | ✅ Full | Excellent | Good debugging tools | | Safari 14+ | ✅ Full | Good | Some limitations | | Edge 79+ | ✅ Full | Excellent | Same as Chrome | | Mobile Chrome | ✅ Full | Good | Optimized for mobile | | Mobile Safari | ⚠️ Limited | Fair | Fallback recommended |
<!-- Automatic fallback configuration -->
<script>
window.SummonConfig = {
preferWasm: true,
fallbackToJs: true,
detectFeatures: true,
loadingTimeout: 10000
};
</script>
# Create optimized production build
./gradlew wasmJsBrowserProductionWebpack
# Files will be in build/distributions/
ls build/distributions/
# -> my-wasm-app.js
# -> my-wasm-app.wasm
# -> index.html
# nginx.conf
server {
listen 80;
server_name yourdomain.com;
# Enable gzip compression
gzip on;
gzip_types
application/wasm
application/javascript
text/css
text/html;
# WASM MIME type
location ~* \.wasm$ {
add_header Content-Type application/wasm;
add_header Cache-Control "public, max-age=31536000";
}
# JavaScript files
location ~* \.js$ {
add_header Content-Type application/javascript;
add_header Cache-Control "public, max-age=31536000";
}
# Main application
location / {
try_files $uri $uri/ /index.html;
}
}
# Upload to CDN with proper headers
aws s3 cp build/distributions/ s3://your-bucket/ --recursive \
--metadata-directive REPLACE \
--content-type "application/wasm" \
--include "*.wasm" \
--cache-control "public, max-age=31536000"
// Add performance monitoring
@Composable
fun MonitoredApp() {
val performanceMetrics = remember { PerformanceTracker() }
LaunchedEffect(Unit) {
performanceMetrics.trackAppStart()
}
App()
}
Problem: Failed to instantiate WebAssembly module
Solution:
<!-- Ensure proper MIME type -->
<script>
// Check if WASM is properly served
fetch('./my-app.wasm')
.then(response => {
console.log('WASM MIME type:', response.headers.get('content-type'));
// Should be 'application/wasm'
});
</script>
Problem: WASM bundle is too large (>1MB)
Solutions:
// 1. Enable dead code elimination
// build.gradle.kts
kotlin {
wasmJs {
browser {
commonWebpackConfig {
optimization {
usedExports = true
sideEffects = false
}
}
}
}
}
// 2. Use code splitting
@Composable
fun LazyLoadedFeature() {
// Split heavy features into separate modules
}
Problem: Out of memory errors in WASM
Solution:
// Monitor memory usage
@Composable
fun MemoryAwareComponent() {
DisposableEffect(Unit) {
val cleanup = {
// Cleanup heavy resources
clearCaches()
System.gc() // Suggest garbage collection
}
onDispose { cleanup() }
}
}
# Enable verbose logging
export SUMMON_DEBUG=true
export WASM_DEBUG=true
# Run with detailed output
./gradlew wasmJsBrowserDevelopmentRun --info
# Browser debugging
# 1. Open Chrome DevTools
# 2. Go to Sources tab
# 3. Look for .wasm files
# 4. Set breakpoints in Kotlin source
// Add WASM target
kotlin {
js(IR) { /* existing JS config */ }
wasmJs { /* new WASM config */ }
}
// src/commonMain/kotlin/SharedComponents.kt
@Composable
fun SharedComponent() {
// Works on both JS and WASM
}
// src/wasmJsMain/kotlin/Main.kt
fun main() {
wasmMain { App() }
}
<!-- Progressive enhancement -->
<script>
if ('WebAssembly' in window) {
import('./app-wasm.js');
} else {
import('./app-js.js');
}
</script>
src/
├── commonMain/kotlin/ # Shared code
│ ├── components/ # UI components
│ ├── models/ # Data models
│ └── utils/ # Utilities
├── wasmJsMain/kotlin/ # WASM-specific code
│ ├── Main.kt # Entry point
│ └── platform/ # Platform-specific implementations
└── jvmMain/kotlin/ # Server-side code
└── ssr/ # SSR implementations
WebAssembly support in Summon provides a powerful platform for building high-performance web applications while maintaining the developer experience and type safety that Kotlin developers expect. With proper setup and optimization, WASM applications can deliver near-native performance in the browser while maintaining full SEO compatibility through server-side rendering.
For more advanced topics and specific use cases, refer to the API Reference and Examples Repository.