-
-
Notifications
You must be signed in to change notification settings - Fork 0
Lazy
-
Name:
Lazy -
Purpose: Lazy-load a Svelte component at runtime via a dynamic
import()and render it with an optionalfallbackwhile loading. - When to use: Code-split a route screen, gate a heavy feature behind on-demand loading, or defer optional UI not needed on first paint.
-
Availability:
@real-router/svelteonly. React/Preact uselazy()+<Suspense>; Vue usesdefineAsyncComponent; Solid useslazy().
<script lang="ts">
import { Lazy } from "@real-router/svelte";
import Spinner from "./Spinner.svelte";
</script>
<Lazy loader={() => import("./HeavyChart.svelte")} fallback={Spinner} />The dynamic import("./HeavyChart.svelte") resolves to a module whose default export is rendered when ready. Until then, <Spinner /> is shown.
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
loader |
() => Promise<{ default: Component }> |
Yes | — | Function that returns a Promise resolving to a module with a default export. Typically () => import(...)
|
fallback |
Component | undefined |
No | undefined |
Component rendered while the loader is pending. Receives no props. |
Lazy keeps internal state in a tagged union (loading | ready | error). On mount, an $effect invokes loader() and:
-
ready: stores the loadeddefaultexport as the active component and renders it. -
error: ifloader()rejects or resolves a module without adefaultexport, the component renders a minimal<p>Error loading component: …</p>and never retries. -
loading: thefallback(if provided) is rendered. Without afallback, nothing is shown.
The $effect cleanup sets an internal active = false flag. If the loader resolves after unmount, state updates are skipped — no setState-after-unmount, no leak. Verified by tests/stress/lazy-loading.stress.ts (30 mount → immediate unmount cycles, discarded results stay bounded).
The loader function is invoked once on mount via the $effect. Passing a new loader reference reactively does NOT re-trigger the load. To swap content, remount via {#key}:
{#key tab}
<Lazy loader={loaders[tab]} fallback={Spinner} />
{/key}Lazy uses $effect, which does NOT run on the server. SSR HTML contains only the fallback (or nothing). On hydration, $effect fires and the loader starts. For SSR-critical data, use state.context.data (via ssr-data-plugin) or a top-level await in <script>.
<!-- Pages.svelte -->
<script lang="ts">
import { Lazy, useRouteNode } from "@real-router/svelte";
import Spinner from "./Spinner.svelte";
const { route } = useRouteNode("");
</script>
{#if route.current?.name === "dashboard"}
<Lazy loader={() => import("./Dashboard.svelte")} fallback={Spinner} />
{:else if route.current?.name === "settings"}
<Lazy loader={() => import("./Settings.svelte")} fallback={Spinner} />
{/if}<Lazy loader={() => import("./BackgroundFeature.svelte")} />Renders nothing until ready; useful for non-critical UI where a spinner would be visually noisy.
A loader resolving without default triggers the error branch:
<Lazy
loader={async () => {
const m = await import("./module");
return m; // No `default` — Lazy will render the error fallback.
}}
/>-
fallbackis a Component, not a Snippet. Pass a Svelte component reference (import Spinner from "./Spinner.svelte") rather than aSnippet. The component receives no props. -
No retry on failure. Once the loader rejects, the error state is terminal until the component is unmounted/remounted (use
{#key retryCount}to force a fresh attempt). -
Error message is plain text. The built-in
<p>Error loading component: {err.message}</p>is intentionally minimal — wrap<Lazy>in an error boundary for richer UX:<RouterErrorBoundary> {#snippet children()} <Lazy loader={() => import("./Heavy.svelte")} fallback={Spinner} /> {/snippet} </RouterErrorBoundary>
-
SSR HTML shows the fallback only. Async content cannot land in the initial HTML — content streams in post-hydration. For SSR data, see the
<Streamed>/<Await>combo orssr-data-plugin.
- Bundler must support dynamic
import()(Vite / Rollup / Webpack 5+ all do). - No router-context dependency —
Lazycan render outside a<RouterProvider>(though the typical use case is inside one).
- Svelte Integration Guide — overview of the adapter surface
-
Streamed — pair
<Lazy>with<Streamed>to add a Suspense-style boundary around multiple lazy children -
RouterErrorBoundary — wrap
<Lazy>to surface loader errors with a friendlier UI
- 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