multiple bug fixes

aaa
Dominic Gannaway 8 months ago
parent 118e28445d
commit 48cf4a25f6

@ -371,11 +371,7 @@ export function client_component(analysis, options) {
const body = b.function_declaration( const body = b.function_declaration(
b.id('$$body'), b.id('$$body'),
[b.id('$$anchor'), b.id('$$props')], [b.id('$$anchor'), b.id('$$props')],
b.block([ b.block([...component_block.body, b.stmt(b.call('$.exit'))])
b.var('$$unsuspend', b.call('$.suspend')),
...component_block.body,
b.stmt(b.call('$$unsuspend'))
])
); );
body.async = true; body.async = true;

@ -1,6 +1,7 @@
/** @import { AwaitExpression, Expression } from 'estree' */ /** @import { AwaitExpression, Expression } from 'estree' */
/** @import { Context } from '../types' */ /** @import { Context } from '../types' */
import * as b from '../../../../utils/builders.js'; import * as b from '../../../../utils/builders.js';
import { get_rune } from '../../../scope.js';
/** /**
* @param {AwaitExpression} node * @param {AwaitExpression} node
@ -13,9 +14,17 @@ export function AwaitExpression(node, context) {
return context.next(); return context.next();
} }
return b.call( const inside_derived = context.path.some(
(n) => n.type === 'CallExpression' && get_rune(n, context.state.scope) === '$derived'
);
const expression = b.call(
b.await( b.await(
b.call('$.save', node.argument && /** @type {Expression} */ (context.visit(node.argument))) b.call('$.save', node.argument && /** @type {Expression} */ (context.visit(node.argument)))
) )
); );
return inside_derived
? expression
: b.await(b.call('$.script_suspend', b.arrow([], expression, true)));
} }

@ -273,13 +273,15 @@ export function capture() {
var previous_reaction = active_reaction; var previous_reaction = active_reaction;
var previous_component_context = component_context; var previous_component_context = component_context;
return function restore() { return function restore(should_exit = true) {
set_active_effect(previous_effect); set_active_effect(previous_effect);
set_active_reaction(previous_reaction); set_active_reaction(previous_reaction);
set_component_context(previous_component_context); set_component_context(previous_component_context);
// prevent the active effect from outstaying its welcome // prevent the active effect from outstaying its welcome
queue_post_micro_task(exit); if (should_exit) {
queue_post_micro_task(exit);
}
}; };
} }
@ -307,6 +309,21 @@ export function suspend() {
}; };
} }
/**
* @template T
* @param {() => Promise<T>} fn
*/
export async function script_suspend(fn) {
const restore = capture();
const unsuspend = suspend();
try {
return await fn();
} finally {
restore(false);
unsuspend();
}
}
/** /**
* @template T * @template T
* @param {Promise<T>} promise * @param {Promise<T>} promise

@ -130,7 +130,7 @@ export {
update_store, update_store,
mark_store_binding mark_store_binding
} from './reactivity/store.js'; } from './reactivity/store.js';
export { boundary, exit, save, suspend } from './dom/blocks/boundary.js'; export { boundary, exit, save, suspend, script_suspend } from './dom/blocks/boundary.js';
export { set_text } from './render.js'; export { set_text } from './render.js';
export { export {
get, get,

@ -29,6 +29,7 @@ import { inspect_effects, internal_set, set_inspect_effects, source } from './so
import { get_stack } from '../dev/tracing.js'; import { get_stack } from '../dev/tracing.js';
import { tracing_mode_flag } from '../../flags/index.js'; import { tracing_mode_flag } from '../../flags/index.js';
import { capture, suspend } from '../dom/blocks/boundary.js'; import { capture, suspend } from '../dom/blocks/boundary.js';
import { flush_boundary_micro_tasks } from '../dom/task.js';
/** /**
* @template V * @template V
@ -99,12 +100,19 @@ export function async_derived(fn) {
var current_deps = new Set(async_deps); var current_deps = new Set(async_deps);
var effect = block(async () => { block(async () => {
var effect = /** @type {Effect} */ (active_effect);
var current = (promise = fn()); var current = (promise = fn());
var restore = capture(); var restore = capture();
var unsuspend = suspend(); var unsuspend = suspend();
// Ensure the effect tree is paused/resume otherwise user-effects will
// not run correctly
if (effect.deps !== null) {
flush_boundary_micro_tasks();
}
try { try {
var v = await promise; var v = await promise;

@ -2,6 +2,14 @@
let { promise, num } = $props(); let { promise, num } = $props();
let value = $derived((await promise) * num); let value = $derived((await promise) * num);
$effect(() => {
console.log('should run');
});
$effect(() => {
console.log(value, num);
});
</script> </script>
<p>{value}</p> <p>{value}</p>

@ -17,12 +17,14 @@ export default test({
}; };
}, },
async test({ assert, target, component }) { async test({ assert, target, component, logs }) {
d.resolve(42); d.resolve(42);
await Promise.resolve(); await Promise.resolve();
await Promise.resolve(); await Promise.resolve();
await Promise.resolve(); await Promise.resolve();
await Promise.resolve(); await Promise.resolve();
await Promise.resolve();
await Promise.resolve();
await tick(); await tick();
flushSync(); flushSync();
assert.htmlEqual(target.innerHTML, '<p>42</p>'); assert.htmlEqual(target.innerHTML, '<p>42</p>');
@ -31,6 +33,8 @@ export default test({
await Promise.resolve(); await Promise.resolve();
await Promise.resolve(); await Promise.resolve();
await Promise.resolve(); await Promise.resolve();
await Promise.resolve();
await Promise.resolve();
await tick(); await tick();
assert.htmlEqual(target.innerHTML, '<p>84</p>'); assert.htmlEqual(target.innerHTML, '<p>84</p>');
@ -42,7 +46,11 @@ export default test({
d.resolve(43); d.resolve(43);
await Promise.resolve(); await Promise.resolve();
await Promise.resolve(); await Promise.resolve();
await Promise.resolve();
await Promise.resolve();
await tick(); await tick();
assert.htmlEqual(target.innerHTML, '<p>86</p>'); assert.htmlEqual(target.innerHTML, '<p>86</p>');
assert.deepEqual(logs, ['should run', 42, 1, 84, 2, 86, 2]);
} }
}); });

@ -19,6 +19,8 @@ export default test({
async test({ assert, target }) { async test({ assert, target }) {
d.resolve('hello'); d.resolve('hello');
await Promise.resolve(); await Promise.resolve();
await Promise.resolve();
await Promise.resolve();
await tick(); await tick();
flushSync(); flushSync();
assert.htmlEqual(target.innerHTML, '<p>hello</p>'); assert.htmlEqual(target.innerHTML, '<p>hello</p>');

Loading…
Cancel
Save