Static rendering vs hydration for edge-deployed SvelteKit pages with runtime-dependent content
0 reputation · 25 Jun 2024, 22:52 UTC
0 reputation · 25 Jun 2024, 22:52 UTC
When deploying a SvelteKit application to an edge platform, pages that incorporate runtime-dependent values—such as timestamps, user-specific data, or feature flags evaluated only on the server—create a tension between two documented rendering modes.
Enabling the default hydrate: true preserves client-side interactivity but risks hydration mismatches when the server-rendered markup diverges from the client's initial render, surfacing as deployment-time errors in the logs. Disabling hydration with hydrate: false guarantees a static HTML payload that never mismatches, yet it defers all interactivity to a later client-side re-hydration step, increasing time-to-interactive for dynamic components.
SvelteKit 1.5 introduced finer-grained prerender controls, but they do not resolve the fundamental trade-off for pages that must reflect server-only state at request time. The documentation acknowledges the choice without prescribing a deterministic rule, leaving the decision to the developer.
Which rendering mode should be chosen for an edge-deployed page that reads a server-only configuration value at request time, requires a button to remain interactive on first load, and must avoid hydration-mismatch failures in production logs?
34275 reputation · 26 Jun 2024, 01:57 UTC
You should choose hydrate: true. Disabling hydration (hydrate: false) removes the Svelte runtime from the client entirely, which would render your buttons non-interactive unless you manually implement raw JavaScript event listeners, failing your primary requirement for first-load interactivity.
The tension arises because SvelteKit's hydration process expects the client's initial render to be identical to the server's HTML. When you inject server-only configuration values (like request-time timestamps or edge-evaluated flags) directly into the markup, the client—which lacks access to those server-side environment variables or request contexts—generates a different DOM tree, triggering the hydration mismatch error.
To maintain interactivity while eliminating production log errors, you must decouple the server-rendered state from the client's initial hydration pass. Use the following pattern:
load: Ensure the server-only value is returned from the +page.server.js load function. This makes the data available to both the server and client via the data prop.onMount.<script>
import { onMount } from 'svelte';
export let data;
let displayValue = '';
onMount(() => {
// This runs only on the client, after the initial DOM is matched
displayValue = data.serverConfigValue;
});
</script>
<p>Config: {displayValue}</p>
<button on:click={handleClick}>Interactive Button</button>
onMount logic populates the runtime value.Diagnostic Detail Needed: Are the runtime-dependent values being passed via the load function, or are they being accessed via server-only modules (e.g., $env/static/private) directly inside the +page.svelte file?
Use comments to ask for clarification. Post a solution as an answer.
34,275 reputation · 26 Jun 2024, 08:30 UTC
Returning a server-only value from +page.server.js makes it available to the client as part of the serialized data prop, even if the component never renders it visibly. That means request-time edge config can appear in the page source or network payload. prerender entries also run at build time, so they cannot capture per-request edge values. To verify, open the rendered page’s HTML or the browser’s network tab and look for the embedded JSON state; if the value appears there, it is no longer server-only.