This document provides detailed API reference for Summon's Server-Side Rendering capabilities. SSR enables rendering Summon components on the server to improve SEO, initial page load times, and user experience.
PlatformRendererThe core abstraction for rendering Summon components across platforms.
abstract class PlatformRenderer {
abstract fun renderComposableRoot(content: @Composable () -> Unit): String
abstract fun renderComposableRootWithHydration(content: @Composable () -> Unit): String
}
renderComposableRoot(content: @Composable () -> Unit): String
content - The root composable to renderrenderComposableRootWithHydration(content: @Composable () -> Unit): String
content - The root composable to renderrenderComposableRootWithHydration(state: Any?, content: @Composable () -> Unit): String
state: The initial state object (should implement UiState or be serializable).content: The root composable to render.JvmPlatformRendererJVM-specific implementation of PlatformRenderer for server-side rendering.
class JvmPlatformRenderer : PlatformRenderer() {
override fun renderComposableRoot(content: @Composable () -> Unit): String
override fun renderComposableRootWithHydration(content: @Composable () -> Unit): String
}
val renderer = JvmPlatformRenderer()
val html = renderer.renderComposableRoot {
MyApp()
}
ServerSideRenderUtilsHigh-level utilities for server-side rendering with additional features.
object ServerSideRenderUtils {
fun renderPageToString(
rootComposable: @Composable () -> Unit,
initialData: Map<String, Any> = emptyMap(),
includeHydrationScript: Boolean = false
): String
fun renderWithSEO(
rootComposable: @Composable () -> Unit,
seoMetadata: SeoMetadata
): String
}
renderPageToString(rootComposable, initialData, includeHydrationScript): String
rootComposable - The root composable to renderinitialData - Initial data to pass to the client for hydrationincludeHydrationScript - Whether to include client-side hydration scriptsrenderWithSEO(rootComposable, seoMetadata): String
rootComposable - The root composable to renderseoMetadata - SEO metadata for the pageRenderContextConfiguration context for SSR operations.
data class RenderContext(
val enableHydration: Boolean = false,
val seoMetadata: SeoMetadata? = null,
val customMetaTags: Map<String, String> = emptyMap(),
val includeViewport: Boolean = true,
val charset: String = "UTF-8"
)
enableHydration: Boolean - Enable client-side hydration supportseoMetadata: SeoMetadata? - SEO metadata configurationcustomMetaTags: Map<String, String> - Additional custom meta tagsincludeViewport: Boolean - Include viewport meta tag for responsive designcharset: String - Character encoding for the documentSeoMetadataComprehensive SEO metadata configuration.
data class SeoMetadata(
val title: String,
val description: String? = null,
val keywords: List<String> = emptyList(),
val author: String? = null,
val canonical: String? = null,
val openGraph: OpenGraphMetadata? = null,
val twitterCard: TwitterCardMetadata? = null,
val robots: String? = null,
val viewport: String? = null
)
title: String - Page titledescription: String? - Meta description for search engineskeywords: List<String> - SEO keywordsauthor: String? - Content authorcanonical: String? - Canonical URL for the pageopenGraph: OpenGraphMetadata? - Open Graph metadata for social sharingtwitterCard: TwitterCardMetadata? - Twitter Card metadatarobots: String? - Robots meta tag contentviewport: String? - Viewport configurationOpenGraphMetadataOpen Graph protocol metadata for rich social media previews.
data class OpenGraphMetadata(
val title: String,
val description: String? = null,
val type: String = "website",
val url: String? = null,
val image: String? = null,
val imageAlt: String? = null,
val siteName: String? = null,
val locale: String? = null
)
title: String - Open Graph titledescription: String? - Open Graph descriptiontype: String - Content type (website, article, etc.)url: String? - Canonical URLimage: String? - Preview image URLimageAlt: String? - Alt text for preview imagesiteName: String? - Site namelocale: String? - Content localeTwitterCardMetadataTwitter Card metadata for Twitter sharing previews.
data class TwitterCardMetadata(
val card: String = "summary",
val site: String? = null,
val creator: String? = null,
val title: String? = null,
val description: String? = null,
val image: String? = null
)
card: String - Twitter card type (summary, summary_large_image, etc.)site: String? - Twitter handle for the websitecreator: String? - Twitter handle for content creatortitle: String? - Twitter card titledescription: String? - Twitter card descriptionimage: String? - Twitter card image URLremember FunctionState management during server-side rendering.
@Composable
fun <T> remember(calculation: () -> T): T
@Composable
fun ServerRenderedComponent() {
val state = remember { mutableStateOf("initial") }
Text("Value: ${state.value}")
}
Note: During SSR, remember creates state that exists only for the duration of the render. For persistent state across client hydration, use appropriate state management patterns.
mutableStateOf FunctionCreates mutable state that works during SSR.
fun <T> mutableStateOf(value: T): MutableState<T>
CompositionLocalProvides composition-local values during SSR.
object CompositionLocal {
fun <T> staticCompositionLocalOf(defaultFactory: () -> T): CompositionLocal<T>
fun <T> compositionLocalOf(defaultFactory: () -> T): CompositionLocal<T>
}
LocalPlatformRenderer - Provides access to the current platform rendererLocalRenderContext - Provides access to the current render contextLocalPlatformRendererComposition local for accessing the platform renderer.
val LocalPlatformRenderer: CompositionLocal<PlatformRenderer?>
@Composable
fun ComponentNeedingRenderer() {
val renderer = LocalPlatformRenderer.current
// Use renderer for nested rendering operations
}
Common errors during server-side rendering:
ComponentNotFoundException - When a required component or renderer is not foundCompositionException - When composition setup failsRenderingException - When HTML generation failstry {
val html = renderer.renderComposableRoot { MyApp() }
} catch (e: ComponentNotFoundException) {
// Handle missing component
} catch (e: CompositionException) {
// Handle composition errors
} catch (e: RenderingException) {
// Handle rendering errors
}
routing {
get("/") {
val renderer = JvmPlatformRenderer()
val html = renderer.renderComposableRoot {
HomePage()
}
call.respondText(html, ContentType.Text.Html)
}
}
@Controller
class PageController {
@GetMapping("/")
fun home(model: Model): String {
val renderer = JvmPlatformRenderer()
val html = renderer.renderComposableRoot {
HomePage()
}
model.addAttribute("content", html)
return "layout"
}
}
@Path("/")
class PageResource {
@GET
@Produces(MediaType.TEXT_HTML)
fun home(): String {
val renderer = JvmPlatformRenderer()
return renderer.renderComposableRoot {
HomePage()
}
}
}
class MockPlatformRenderer : PlatformRenderer() {
override fun renderComposableRoot(content: @Composable () -> Unit): String {
// Mock implementation for testing
}
}
@Test
fun testSSRComponent() {
val renderer = JvmPlatformRenderer()
val html = renderer.renderComposableRoot {
TestComponent()
}
assertTrue(html.contains("expected content"))
}
LaunchedEffect or DisposableEffect