Markup Yield Syntax
Relevant source files
The following files were used as context for generating this wiki page:
- skills/svelte-effect-runtime/references/syntax.md
- modules/svelte-effect-runtime/src/markup/transform/index.ts
- modules/svelte-effect-runtime/src/markup/transform/scan.ts
- modules/svelte-effect-runtime/src/markup/transform/types.ts
- modules/svelte-effect-runtime/src/diagnostics.ts
- modules/svelte-effect-runtime/src/markup/transform/apply.ts
Markup Yield Syntax is a compile-time feature of the Svelte Effect Runtime (SER) that enables Svelte components to use effectful programs directly within markup. It allows developers to use the yield* operator inside brace expressions to perform asynchronous or effectful work, such as fetching data or executing business logic, without manually managing Svelte's onMount or reactive statements.
The system works through a transformation pipeline that scans .svelte files for yield* expressions, replaces them with stable placeholders for Svelte's compiler, and then lowers those expressions into generated dispatcher events and reactive bindings. This ensures that the effect lifecycle—including cancellation and error handling—is managed automatically by the SER runtime.
Sources: modules/svelte-effect-runtime/src/markup/transform/index.ts:32-41, skills/svelte-effect-runtime/references/syntax.md:33-40
Core Syntax and Supported Positions
SER supports the use of yield* in a variety of Svelte markup contexts. The transform process identifies these positions to ensure the generated code respects Svelte's architectural boundaries.
Supported Markup Contexts
The following table summarizes where yield* can be utilized within Svelte markup:
| Context | Example |
|---|---|
| Interpolation | {yield* render_name(user_id)} |
| Conditionals | {#if yield* has_access(user_id)} |
| Loops | {#each yield* list_projects() as project} |
| Await Blocks | {#await yield* load_report(id)} |
| Key Blocks | {#key yield* get_version()} ... {/key} |
| Declaration Tags | {const price = yield* load_price(symbol)} |
| Event Handlers | onclick={yield* save(id)} |
Sources: skills/svelte-effect-runtime/references/syntax.md:42-63, modules/svelte-effect-runtime/src/markup/transform/types.ts:145-154
Event Handler Requirements
Effectful event handlers must use a specific yield-first syntax. The SER transform generates the necessary event parameters for direct handlers. Importantly, yield* cannot be hidden inside a callback function within an event attribute; it must reside at the top level of the attribute expression.
- Valid:
onclick={yield* save(id)} - Invalid:
onclick={() => yield* save(id)}
Sources: skills/svelte-effect-runtime/references/syntax.md:72-84, modules/svelte-effect-runtime/src/diagnostics.ts:135-144
Transformation Pipeline
The transformation of markup yield expressions occurs in several distinct phases to maintain source mapping and handle Svelte's specific parsing requirements.
Phase 1: Sanitization and Scanning
The process begins by scanning the raw content for yield* occurrences. To prevent TypeScript-heavy <script> blocks from breaking the Svelte parser, script blocks are temporarily "blanked" while the markup is analyzed.
The diagram shows the high-level flow of the markup transformation pipeline from raw input to generated code.
Sources: modules/svelte-effect-runtime/src/markup/transform/index.ts:51-92, modules/svelte-effect-runtime/src/markup/transform/scan.ts:44-55
Phase 2: Classification and Placeholder Mapping
Because yield* is not valid standard Svelte syntax, the sanitize_markup function replaces these expressions with unique identifiers (e.g., __SER___markup_placeholder_0). After Svelte's AST parses the "clean" markup, the classify_candidates function matches these placeholders back to their intended Svelte context (e.g., #each, @render, or an event).
Sources: modules/svelte-effect-runtime/src/markup/transform/index.ts:77-84, modules/svelte-effect-runtime/src/markup/transform/scan.ts:75-88
Phase 3: Lowering and Injection
The final phase replaces placeholders with reactive reads and injects helper code into the component's instance script.
- Helper Injection: The transform ensures the
get_dispatcherand related runtime helpers are imported and initialized. - Relocation: The system tracks
MarkupRelocationranges to preserve hoverable source spans in the editor even after the code has been significantly rewritten.
Sources: modules/svelte-effect-runtime/src/markup/transform/apply.ts:98-125, modules/svelte-effect-runtime/src/markup/transform/types.ts:70-81
Diagnostics and Validation
SER provides specific diagnostics to catch common misuse of effectful markup. These diagnostics help developers avoid "sync-only" pitfalls where an Effect might be created but not executed.
Diagnostic Rules
The find_svelte_effect_diagnostics function checks for the following issues:
- Hidden Yields: Detecting
yield*inside a callback (e.g., an arrow function) instead of at the attribute boundary. - Explicit Runners: Warning when
Effect.runPromiseor similar runners are used manually, which bypasses SER's automatic cancellation. - Bare Effect.gen: Detecting
Effect.genused as a value without a correspondingyield*. - Attribute Effects: Detecting attributes that receive an Effect object instead of its resolved value.
Sources: modules/svelte-effect-runtime/src/diagnostics.ts:76-130, skills/svelte-effect-runtime/references/validation.md:24-33
Implementation Details
Diagnostics use a character-based scanner to find brace expressions and regex-based analysis to determine if the expression references Effect primitives.
The sequence diagram illustrates the diagnostic check flow for identifying invalid SER usage in markup.
Sources: modules/svelte-effect-runtime/src/diagnostics.ts:161-224
Technical Summary of Components
| Component | Responsibility |
|---|---|
transform_markup_effect | Entry point for transforming .svelte markup. |
sanitize_markup | Replaces yield* with stable placeholders for Svelte parsing. |
classify_candidates | Determines the AST context of each placeholder. |
emit_replacements | Generates the dispatcher calls and reactive bindings. |
inject_helpers | Handles the insertion of import and const dispatcher statements. |
Sources: modules/svelte-effect-runtime/src/markup/transform/index.ts:12-25, modules/svelte-effect-runtime/src/markup/transform/scan.ts:44-50, modules/svelte-effect-runtime/src/markup/transform/apply.ts:42-55
Markup Yield Syntax provides a seamless bridge between Svelte's reactive rendering and the Effect ecosystem. By leveraging a multi-stage transform that includes sanitization, AST classification, and helper injection, SER allows for concise, intentful code while maintaining technical correctness and robust resource management through the centralized dispatcher.