Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/itchy-hats-study.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

fix: always allow `setContext` before first await in component
1 change: 1 addition & 0 deletions packages/svelte/src/internal/client/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const INERT = 1 << 13;
export const DESTROYED = 1 << 14;

// Flags exclusive to effects
/** Set once an effect that should run synchronously has run */
export const EFFECT_RAN = 1 << 15;
/**
* 'Transparent' effects do not create a transition boundary.
Expand Down
9 changes: 8 additions & 1 deletion packages/svelte/src/internal/client/context.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,11 @@ export function setContext(key, context) {

if (async_mode_flag) {
var flags = /** @type {Effect} */ (active_effect).f;
var valid = !active_reaction && (flags & BRANCH_EFFECT) !== 0 && (flags & EFFECT_RAN) === 0;
var valid =
!active_reaction &&
(flags & BRANCH_EFFECT) !== 0 &&
// pop() runs synchronously, so this indicates we're setting context after an await
!(/** @type {ComponentContext} */ (component_context).i);

if (!valid) {
e.set_context_after_init();
Expand Down Expand Up @@ -173,6 +177,7 @@ export function getAllContexts() {
export function push(props, runes = false, fn) {
component_context = {
p: component_context,
i: false,
c: null,
e: null,
s: props,
Expand Down Expand Up @@ -208,6 +213,8 @@ export function pop(component) {
context.x = component;
}

context.i = true;

component_context = context.p;

if (DEV) {
Expand Down
4 changes: 2 additions & 2 deletions packages/svelte/src/internal/client/error-handling.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export function handle_error(error) {
// if the error occurred while creating this subtree, we let it
// bubble up until it hits a boundary that can handle it
if ((effect.f & BOUNDARY_EFFECT) === 0) {
if (!effect.parent && error instanceof Error) {
if (DEV && !effect.parent && error instanceof Error) {
apply_adjustments(error);
}

Expand Down Expand Up @@ -61,7 +61,7 @@ export function invoke_error_boundary(error, effect) {
effect = effect.parent;
}

if (error instanceof Error) {
if (DEV && error instanceof Error) {
apply_adjustments(error);
}

Expand Down
4 changes: 3 additions & 1 deletion packages/svelte/src/internal/client/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Store } from '#shared';
import { STATE_SYMBOL } from './constants.js';
import type { Effect, Source, Value, Reaction } from './reactivity/types.js';
import type { Effect, Source, Value } from './reactivity/types.js';

type EventCallback = (event: Event) => boolean;
export type EventCallbackMap = Record<string, EventCallback | EventCallback[]>;
Expand All @@ -16,6 +16,8 @@ export type ComponentContext = {
c: null | Map<unknown, unknown>;
/** deferred effects */
e: null | Array<() => void | (() => void)>;
/** True if initialized, i.e. pop() ran */
i: boolean;
/**
* props — needed for legacy mode lifecycle functions, and for `createEventDispatcher`
* @deprecated remove in 6.0
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { tick } from 'svelte';
import { test } from '../../test';

export default test({
mode: ['client'],
async test() {
// else runtime_error is checked too soon
await tick();
},
runtime_error: 'set_context_after_init'
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<script>
import { setContext } from 'svelte';
await Promise.resolve('hi');
setContext('key', 'value');
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<script lang="ts">
import { getContext } from "svelte";

let greeting = getContext("greeting");
</script>

<p>{greeting}</p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<script lang="ts">
import { setContext } from "svelte";
import Inner from "./Inner.svelte";

setContext("greeting", "hi");
await Promise.resolve();
</script>

<Inner />
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { tick } from 'svelte';
import { test } from '../../test';

export default test({
mode: ['client', 'async-server'],
ssrHtml: `<p>hi</p>`,
async test({ assert, target }) {
await tick();
assert.htmlEqual(target.innerHTML, '<p>hi</p>');
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<script lang="ts">
import Outer from "./Outer.svelte";

await Promise.resolve();
</script>

<Outer />
Loading