sveltejs/svelte
Client runtime
Active contributors: Rich Harris, Simon H, Dominic Gannaway
Purpose
The client runtime is the JavaScript that compiled .svelte components import to mount, hydrate, react, and update the DOM. It lives entirely under packages/svelte/src/internal/client/ and is exposed to compiled code as svelte/internal/client (subpath defined in packages/svelte/package.json).
User-facing entries — mount, hydrate, unmount, tick, untrack, flushSync, getContext, onMount, etc. — are re-exported from packages/svelte/src/index-client.js.
Directory layout
src/internal/client/
├── render.js # mount / hydrate / unmount entry points
├── runtime.js # active reaction tracking, update_effect
├── context.js # ComponentContext, push/pop
├── reactivity/
│ ├── sources.js # leaf reactive values
│ ├── deriveds.js # memoised reactions
│ ├── effects.js # side-effectful reactions
│ ├── batch.js # microtask scheduler, flushSync, fork
│ ├── async.js # async reaction support
│ ├── store.js # store ↔ reactivity bridge
│ ├── props.js # $props, $bindable plumbing
│ ├── equality.js, status.js, types.d.ts, utils.js
├── proxy.js # deep-reactive Proxy for $state(object)
├── error-handling.js # boundary integration
├── dom/
│ ├── operations.js # createElement, append, etc. wrappers
│ ├── template.js # parsed template caching
│ ├── reconciler.js # task scheduler
│ ├── task.js # rAF/microtask helper
│ ├── hydration.js # cursor-based hydration walker
│ ├── css.js # scoped style insertion
│ ├── blocks/ # one file per block kind (if/each/await/...)
│ ├── elements/ # actions, attachments, attributes, bindings, events, transitions
│ └── legacy/ # Svelte 4 lifecycle + event modifiers
├── dev/ # dev-only helpers (HMR, tracing, $inspect, ownership, ...)
├── flags/, hydratable.js, legacy.js, loop.js, timing.js
└── constants.js # bitmask flags (CLEAN, DIRTY, DERIVED, ...)Mount, hydrate, unmount
packages/svelte/src/internal/client/render.js exports the three main lifecycle entry points. They share an internal _mount helper that:
- Initialises low-level DOM operations (
init_operationsfromdom/operations.js). - Creates a fresh
ComponentContext(context.js) and pushes it onto the stack. - Runs the compiled component function inside a
component_rooteffect (reactivity/effects.js). - Returns the component's exports object.
hydrate flips a global hydrating flag and walks server-rendered comment markers (HYDRATION_START / HYDRATION_END) to attach reactivity without re-creating the DOM. The walker primitives live in dom/hydration.js.
unmount tears down the root effect, which recursively destroys child blocks, runs teardown callbacks, and removes event listeners.
Blocks
Each block in template syntax compiles to a runtime call. The block runtime functions live one-per-file under dom/blocks/:
| Block syntax | File |
|---|---|
{#if} |
blocks/if.js |
{#each} |
blocks/each.js (~18 KB, the largest) |
{#await} |
blocks/await.js |
{#key} |
blocks/key.js |
{#snippet} / {@render} |
blocks/snippet.js |
{@html} |
blocks/html.js |
{@async} |
blocks/async.js |
<svelte:component> |
blocks/svelte-component.js |
<svelte:element> |
blocks/svelte-element.js |
<svelte:head> |
blocks/svelte-head.js |
<svelte:boundary> |
blocks/boundary.js (~13 KB) |
<slot> |
blocks/slot.js |
| CSS custom properties | blocks/css-props.js |
branches |
blocks/branches.js |
Element-level helpers
Generated DOM updates rely on helpers under dom/elements/:
- Attributes:
attributes.js(~20 KB) handlesset_attribute, boolean attribute correction, hydration mismatches, and theclass/styledirectives.class.jsandstyle.jsare companions. - Events:
events.js(~11 KB) implements event delegation, modifier wrapping (legacy/event-modifiers.js), andadd_event_listener. - Bindings:
bindings/is the largest sub-tree — input, media, navigator (bind:online), props, select, size (bind:contentRect), this, universal (bind:innerHTML), and window scroll/size bindings. Each one creates a reciprocalSource↔ DOM listener. - Transitions:
transitions.js(~14 KB) coordinates intro/outro transitions and theanimate:directive. See Transitions. - Actions / attachments:
actions.js(legacyuse:) andattachments.js(modern{@attach}). - Custom elements:
custom-element.js(~10 KB) implements<svelte:options customElement>. - Customizable select:
customizable-select.jsis the polyfill helpers for<selectedcontent>.
Reactivity primitives
See Reactivity engine for the deep dive. The five files that matter are:
| File | What it owns |
|---|---|
internal/client/runtime.js |
active_reaction, update_effect, get, dependency tracking. |
internal/client/reactivity/sources.js |
state(...), set(...), increment(...), flush_eager_effects. |
internal/client/reactivity/deriveds.js |
derived(...), recompute logic, freeze/unfreeze. |
internal/client/reactivity/effects.js |
effect(...), branch(...), teardown semantics. |
internal/client/reactivity/batch.js |
Batch, flushSync, fork, scheduling. |
Public exports
packages/svelte/src/index-client.js is what user code imports as svelte:
export { flushSync, fork } from './internal/client/reactivity/batch.js';
export {
createContext,
getContext,
getAllContexts,
hasContext,
setContext,
} from './internal/client/context.js';
export { hydratable } from './internal/client/hydratable.js';
export { hydrate, mount, unmount } from './internal/client/render.js';
export { tick, untrack, settled } from './internal/client/runtime.js';
export { createRawSnippet } from './internal/client/dom/blocks/snippet.js';
// + getAbortSignal, onMount, onDestroy, createEventDispatcher, beforeUpdate, afterUpdate (deprecated)The DEV builds also install global getters for $state, $effect, $derived, $inspect, $props, $bindable that throw rune_outside_svelte errors if accessed outside a component context — see the top of index-client.js.
Dev-only helpers
internal/client/dev/ bundles features that are only included in DEV builds via import { DEV } from 'esm-env':
tracing.js—$inspect.traceintegration, captures stack traces for each reaction update.hmr.js— hot module replacement marker class and re-mount logic.inspect.js—$inspect(value)log integration.ownership.js— warns when a component mutates state owned by another component.legacy.js,validation.js,assign.js,css.js,elements.js— additional dev-only checks.
These are listed in internal/client/index.js so the compiler can address them by name.
Key source files
| File | Purpose |
|---|---|
packages/svelte/src/internal/client/render.js |
mount, hydrate, unmount plus set_text. |
packages/svelte/src/internal/client/runtime.js |
Reaction tracking, scheduling glue. |
packages/svelte/src/internal/client/context.js |
ComponentContext, push/pop, context API. |
packages/svelte/src/internal/client/proxy.js |
Deep-reactive Proxy. |
packages/svelte/src/internal/client/dom/blocks/each.js |
The keyed/non-keyed list reconciler. |
packages/svelte/src/internal/client/dom/elements/attributes.js |
Attribute setting, hydration mismatch repair. |
packages/svelte/src/internal/client/dom/elements/events.js |
Event delegation, modifier handling. |
packages/svelte/src/internal/client/error-handling.js |
<svelte:boundary> integration. |
Entry points for modification
To add a new template block, you need: a new visitor under phases/3-transform/client/visitors/, a new file under internal/client/dom/blocks/, and an export in internal/client/index.js. To add a new binding, add a file under dom/elements/bindings/ and a bind_* export. To change reactivity semantics, the four places to look are runtime.js, reactivity/effects.js, reactivity/sources.js, and reactivity/batch.js.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.