Skip to content
Open
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
3 changes: 2 additions & 1 deletion packages/svelte/src/compiler/phases/1-parse/utils/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ export function create_fragment(transparent = false) {
metadata: {
transparent,
dynamic: false,
has_await: false
has_await: false,
effect_pending_expressions: []
}
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,22 @@ export function CallExpression(node, context) {
break;

case '$effect.pending':
if (node.arguments.length > 1) {
e.rune_invalid_arguments_length(node, rune, 'zero or one arguments');
}

if (context.state.expression) {
context.state.expression.has_state = true;
}

if (node.arguments[0]) {
const fragment = /** @type {AST.Fragment} */ (context.state.fragment);

fragment.metadata.effect_pending_expressions.push(
/** @type {Expression} */ (node.arguments[0])
);
}

break;

case '$inspect':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ export interface ClientTransformState extends TransformState {
/** `true` if we're transforming the contents of `<script>` */
readonly is_instance: boolean;

effect_pending: Map<Expression, Identifier>;

readonly transform: Record<
string,
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,17 @@ export function CallExpression(node, context) {
);

case '$effect.pending':
if (node.arguments[0]) {
const id = b.id(`$$pending_${context.state.effect_pending.size}`);

context.state.effect_pending.set(
/** @type {Expression} */ (context.visit(node.arguments[0])),
id
);

return b.call('$.get', id);
}

return b.call('$.pending');

case '$inspect':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export function Fragment(node, context) {
memoizer: new Memoizer(),
template: new Template(),
transform: { ...context.state.transform },
effect_pending: new Map(),
metadata: {
namespace,
bound_contenteditable: context.state.metadata.bound_contenteditable
Expand Down Expand Up @@ -152,6 +153,10 @@ export function Fragment(node, context) {

body.push(...state.consts);

for (const [expression, id] of state.effect_pending) {
body.push(b.const(id, b.call('$.pending', b.thunk(expression))));
}

if (has_await) {
body.push(b.if(b.call('$.aborted'), b.return()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,8 @@ export function RegularElement(node, context) {
metadata,
scope: /** @type {Scope} */ (context.state.scopes.get(node.fragment)),
preserve_whitespace:
context.state.preserve_whitespace || node.name === 'pre' || node.name === 'textarea'
context.state.preserve_whitespace || node.name === 'pre' || node.name === 'textarea',
effect_pending: new Map()
};

const { hoisted, trimmed } = clean_nodes(
Expand Down Expand Up @@ -378,6 +379,10 @@ export function RegularElement(node, context) {
}
}

for (const [expression, id] of state.effect_pending) {
child_state.init.push(b.const(id, b.call('$.pending', b.thunk(expression))));
}

if (node.fragment.nodes.some((node) => node.type === 'SnippetBlock')) {
// Wrap children in `{...}` to avoid declaration conflicts
context.state.init.push(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export function CallExpression(node, context) {
}

if (rune === '$effect.pending') {
return b.literal(0);
return node.arguments[0] ?? b.literal(0);
}

if (rune === '$state' || rune === '$state.raw') {
Expand Down
1 change: 1 addition & 0 deletions packages/svelte/src/compiler/types/template.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export namespace AST {
*/
dynamic: boolean;
has_await: boolean;
effect_pending_expressions: Expression[];
};
}

Expand Down
34 changes: 32 additions & 2 deletions packages/svelte/src/internal/client/dom/blocks/boundary.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@ import {
import { HYDRATION_START_ELSE } from '../../../../constants.js';
import { component_context, set_component_context } from '../../context.js';
import { handle_error, invoke_error_boundary } from '../../error-handling.js';
import { block, branch, destroy_effect, pause_effect } from '../../reactivity/effects.js';
import {
block,
branch,
destroy_effect,
inspect_effect,
pause_effect
} from '../../reactivity/effects.js';
import {
active_effect,
active_reaction,
Expand All @@ -33,6 +39,7 @@ import { Batch, current_batch, effect_pending_updates } from '../../reactivity/b
import { internal_set, source } from '../../reactivity/sources.js';
import { tag } from '../../dev/tracing.js';
import { createSubscriber } from '../../../../reactivity/create-subscriber.js';
import { untrack } from 'svelte';

/**
* @typedef {{
Expand Down Expand Up @@ -440,7 +447,10 @@ export function get_boundary() {
return /** @type {Boundary} */ (/** @type {Effect} */ (active_effect).b);
}

export function pending() {
/**
* @param {(() => any) | void} fn
*/
export function pending(fn) {
if (active_effect === null) {
e.effect_pending_outside_reaction();
}
Expand All @@ -451,5 +461,25 @@ export function pending() {
return 0; // TODO eventually we will need this to be global
}

if (fn) {
const signal = source(untrack(fn));

inspect_effect(() => {
const value = fn();
let stale = false;

queue_micro_task(() => {
if (stale) return;
internal_set(signal, value);
});

return () => {
stale = true;
};
});

return signal;
}

return boundary.get_effect_pending();
}
Loading