mirror of https://github.com/sveltejs/svelte
This associates the current batch with the boundary when entering pending mode. That way other async work associated to that boundary also can associate itself with that batch, even if e.g. due to flushing it is no longer the current batch. This solves a null pointer exception that can occur when the batch is flushed before the next top level await or async derived gets a hold of the current batch, which is null then. Fixes #16596 Fixes https://github.com/sveltejs/kit/issues/14124boundary-batch-nullpointer-fix
parent
2e02868ef1
commit
e14561c829
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: associate batch with boundary
|
@ -0,0 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { resolve } from './main.svelte';
|
||||
|
||||
const bar = await new Promise((r) => resolve.push(() => r('bar')));
|
||||
</script>
|
||||
|
||||
<p>bar: {bar}</p>
|
@ -0,0 +1,10 @@
|
||||
<script lang="ts">
|
||||
import { resolve } from './main.svelte';
|
||||
import Bar from './Bar.svelte';
|
||||
|
||||
const foo = await new Promise((r) => resolve.push(() => r('foo')));
|
||||
</script>
|
||||
|
||||
<p>foo: {foo}</p>
|
||||
|
||||
<Bar/>
|
@ -0,0 +1,42 @@
|
||||
import { tick } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
async test({ assert, target }) {
|
||||
const [show, resolve] = target.querySelectorAll('button');
|
||||
|
||||
show.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button>show</button>
|
||||
<button>resolve</button>
|
||||
<p>pending...</p>
|
||||
`
|
||||
);
|
||||
|
||||
resolve.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button>show</button>
|
||||
<button>resolve</button>
|
||||
<p>pending...</p>
|
||||
`
|
||||
);
|
||||
|
||||
resolve.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button>show</button>
|
||||
<button>resolve</button>
|
||||
<p>foo: foo</p>
|
||||
<p>bar: bar</p>
|
||||
`
|
||||
);
|
||||
}
|
||||
});
|
@ -0,0 +1,31 @@
|
||||
<script module>
|
||||
export let resolve = [];
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import Foo from './Foo.svelte';
|
||||
|
||||
let show = $state(false);
|
||||
</script>
|
||||
|
||||
<button onclick={() => show = true}>
|
||||
show
|
||||
</button>
|
||||
|
||||
<button onclick={() => resolve.shift()()}>
|
||||
resolve
|
||||
</button>
|
||||
|
||||
<svelte:boundary>
|
||||
{#if show}
|
||||
<Foo/>
|
||||
{/if}
|
||||
|
||||
{#if $effect.pending()}
|
||||
<p>pending...</p>
|
||||
{/if}
|
||||
|
||||
{#snippet pending()}
|
||||
<p>initializing...</p>
|
||||
{/snippet}
|
||||
</svelte:boundary>
|
@ -0,0 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { resolve } from './main.svelte';
|
||||
|
||||
const foo = $derived(await new Promise((r) => resolve.push(() => r('foo'))));
|
||||
const bar = $derived(await new Promise((r) => resolve.push(() => r('bar'))));
|
||||
</script>
|
||||
|
||||
<p>{foo} {bar}</p>
|
@ -0,0 +1,41 @@
|
||||
import { tick } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
async test({ assert, target }) {
|
||||
const [show, resolve] = target.querySelectorAll('button');
|
||||
|
||||
show.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button>show</button>
|
||||
<button>resolve</button>
|
||||
<p>pending...</p>
|
||||
`
|
||||
);
|
||||
|
||||
resolve.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button>show</button>
|
||||
<button>resolve</button>
|
||||
<p>pending...</p>
|
||||
`
|
||||
);
|
||||
|
||||
resolve.click();
|
||||
await tick();
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<button>show</button>
|
||||
<button>resolve</button>
|
||||
<p>foo bar</p>
|
||||
`
|
||||
);
|
||||
}
|
||||
});
|
@ -0,0 +1,31 @@
|
||||
<script module>
|
||||
export let resolve = [];
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import Foo from './Foo.svelte';
|
||||
|
||||
let show = $state(false);
|
||||
</script>
|
||||
|
||||
<button onclick={() => show = true}>
|
||||
show
|
||||
</button>
|
||||
|
||||
<button onclick={() => resolve.shift()()}>
|
||||
resolve
|
||||
</button>
|
||||
|
||||
<svelte:boundary>
|
||||
{#if show}
|
||||
<Foo/>
|
||||
{/if}
|
||||
|
||||
{#if $effect.pending()}
|
||||
<p>pending...</p>
|
||||
{/if}
|
||||
|
||||
{#snippet pending()}
|
||||
<p>initializing...</p>
|
||||
{/snippet}
|
||||
</svelte:boundary>
|
Loading…
Reference in new issue