-
-
Notifications
You must be signed in to change notification settings - Fork 0
Streamed
-
Name:
Streamed -
Purpose: Cross-adapter alias for the framework's native Suspense / await boundary. Renders a
fallbackwhile apendingPromise (or any descendant<Await>) is unresolved, thenchildrenwith the resolved value. -
When to use: Wrap a region of UI that depends on deferred SSR data when you want cross-framework symmetric naming. Inside a single framework, you can also use the native primitive (
<Suspense>in React/Preact,{#await}in Svelte) directly. -
Availability: All 5 framework adapters —
@real-router/react/ssr,@real-router/preact/ssr,@real-router/solid/ssr,@real-router/vue/ssr,@real-router/svelte/ssr. The Svelte variant wraps the native{#await}block (no<Suspense>in Svelte).
<script lang="ts">
import { Streamed, useDeferred } from "@real-router/svelte/ssr";
import Spinner from "./Spinner.svelte";
interface Review {
id: string;
text: string;
}
const reviewsPromise = useDeferred<Review[]>("reviews");
</script>
<Streamed pending={reviewsPromise}>
{#snippet children(reviews)}
<ReviewList items={reviews} />
{/snippet}
{#snippet fallback()}
<Spinner />
{/snippet}
</Streamed>| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
pending |
Promise<T> |
Yes | — | Promise to await — typically the return value of useDeferred<T>(key) or any user-supplied Promise. |
children |
Snippet<[T]> |
Yes | — | Render snippet for the resolved value. Receives the awaited value as its single positional argument. |
fallback |
Snippet |
No | undefined |
Snippet rendered while pending is unresolved. Omit for silent loading. |
Internally <Streamed> is a single {#await pending}…{:then value}…{/await} block:
{#await pending}
<Fallback />
{:then value}
<Children {value} />
{/await}No additional logic — it exists purely for cross-adapter naming symmetry. Teams using multiple framework adapters (e.g. a monorepo with both React and Svelte apps) can reuse mental models when reading templates.
-
Prefer
<Streamed>when you want consistent naming with other framework adapters in your codebase, or when sharing template patterns with documentation that uses cross-framework examples. -
Prefer
{#await}directly when you need the{:catch error}branch for rejection handling, or when the rest of the codebase uses Svelte-idiomatic patterns.
| Aspect | <Streamed> |
<Await> |
|---|---|---|
| Promise source | Caller passes pending directly |
Reads useDeferred(name) internally via key |
| Reactivity | Promise reference must be reactive (typically $state or $derived) |
name is reactive via $derived(useDeferred(name))
|
| Symmetry | Cross-framework <Streamed fallback={…}>
|
Cross-framework <Await name="…">
|
| Use case | Any awaitable, not only deferred | Specifically reads SSR state.context.ssrDataDeferred[key]
|
You can nest them — <Streamed> as the boundary, <Await> for individual deferred reads:
<Streamed pending={useDeferred("hero")}>
{#snippet children(hero)}
<HeroSection {hero} />
<Await name="reviews">
{#snippet children(reviews)}
<ReviewList items={reviews} />
{/snippet}
</Await>
{/snippet}
{#snippet fallback()}
<ProductSkeleton />
{/snippet}
</Streamed>Svelte 5 stable does NOT progressively chunk-flush HTTP for {#await} blocks. On the server:
-
<Streamed>emits the fallback branch in the initial HTML. - The full response ships in one TCP frame; no out-of-order chunks.
- After hydration, the client re-runs the
{#await}and resolves the promise, swapping inchildren(value).
This is RSC-like (server shell + client data) rather than React 19 / Solid streaming (chunked HTTP + OOO placeholders). See Streaming SSR for the framework-by-framework comparison.
<Streamed> has no {:catch} branch. Rejections propagate to the surrounding {#await}/<Streamed> chain (i.e. they crash uncaught if no parent handles them). For fine-grained error UX, use raw {#await}…{:catch error}…{/await} or wrap with <RouterErrorBoundary>.
<script lang="ts">
import { Streamed, Await, useDeferred } from "@real-router/svelte/ssr";
import Spinner from "./Spinner.svelte";
</script>
<Streamed pending={useDeferred("hero")}>
{#snippet children(hero)}
<HeroSection {hero} />
<Await name="reviews">
{#snippet children(reviews)}
<ReviewList items={reviews} />
{/snippet}
{#snippet fallback()}
<Spinner label="Loading reviews" />
{/snippet}
</Await>
{/snippet}
{#snippet fallback()}
<ProductSkeleton />
{/snippet}
</Streamed><script lang="ts">
import { Streamed } from "@real-router/svelte/ssr";
// Plain promise — doesn't have to come from useDeferred.
let dataPromise = fetch("/api/widgets").then((r) => r.json());
</script>
<Streamed pending={dataPromise}>
{#snippet children(widgets)}
<WidgetGrid items={widgets} />
{/snippet}
{#snippet fallback()}
<Spinner />
{/snippet}
</Streamed>{#await dataPromise}
<Spinner />
{:then items}
<WidgetGrid {items} />
{:catch error}
<ErrorBanner message={error.message} />
{/await}-
No
{:catch}branch. Use raw{#await}for rejection UX. -
fallbackis a Snippet, not a Component. Different from<Lazy>, which takes a Component reference.{#snippet fallback()}is the Svelte-5-idiomatic way. - Server response is monolithic. Despite the "streaming" name, Svelte 5 stable returns the full HTML in one TCP frame. Deferred resolution happens client-side. See Streaming SSR for the model comparison.
-
The
pendingprop is not "captured at mount". It's reactive — if you pass a$stateor$derivedPromise reference, the{#await}re-runs when the reference changes.
- No
<RouterProvider>requirement —<Streamed>can wrap any Promise. - For
useDeferred-fed Promises, a router withssr-data-pluginmust be mounted (see<Await>for context).
-
Await — pair with
<Streamed>to read deferred SSR data by key - useDeferred — composable that returns the underlying Promise
- Streaming SSR — cross-framework streaming model comparison
- Svelte Integration Guide — overview of the SSR surface
-
Lazy — lazy-load a single component (different concept: dynamic
import()of a module)
- View-Agnostic Design
- Core Concepts
- Navigation Lifecycle
- Guards
- Plugin Architecture
- Hash Fragment Support
- Accessibility (A11y)
- Server-Side Rendering
- Data Loading
- Streaming SSR
- SSR Cancellation
- RSC Integration
- Testing
- Glossary
Tree-shakeable functions — import only what you need.
- add (addRoute)
- remove (removeRoute)
- replace (replaceRoutes)
- clear (clearRoutes)
- get (getRoute)
- has (hasRoute)
- update (updateRoute)
- get (getDependency)
- getAll (getDependencies)
- set (setDependency)
- setAll (setDependencies)
- has (hasDependency)
- remove (removeDependency)
- reset (resetDependencies)
For plugin authors, not for general use.
- makeState
- buildState
- buildNavigationState
- forwardState
- getForwardState
- setForwardState
- matchPath
- setRootPath
- getRootPath
- navigateToState
- addEventListener
- getRouteConfig
- getOptions
- addBuildPathInterceptor
- extendRouter
- getTree
- React Integration Guide
- Preact Integration Guide
- Solid Integration Guide
- Vue Integration Guide
- Svelte Integration Guide
- Ink (Terminal UI) Integration Guide
- Desktop (Electron, Tauri) Integration Guide
- useRouter
- useRoute
- useRouteNode
- useNavigator
- useRouteUtils
- useRouterTransition
- useRouteExit
- useRouteEnter
- useRouteStore (Solid only)
- useRouteNodeStore (Solid only)
SSR-feature subpath —
@real-router/{adapter}/ssr. Symmetric across React/Preact/Solid/Vue/Svelte.
- Lazy (Svelte only — dynamic component import)
- Await — read deferred SSR data by key
- Streamed — Suspense-style boundary
- ClientOnly — server fallback → client children swap
- ServerOnly — server children, removed after hydration
- HttpStatusCode — render-time HTTP status declaration
-
HttpStatusProvider — provides sink to descendant
<HttpStatusCode> - useDeferred — read deferred Promise by key