mirror of https://github.com/sveltejs/svelte
fix: make template store subscriptions wait for the promise that assigns the store (#18582)
Blockers didn't include analyzing implicit store subscriptions, which could also only happen in the template. Also needs to defer store unsubscribe until after the async template has settled in case the store value is read after an async blocker, in which case unsubscribe synchronously is too soon. Fixes https://github.com/sveltejs/kit/issues/15119pull/18685/head
parent
2d2e5df26e
commit
9d0062d607
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: block template store subscriptions on the promise that assigns the store
|
||||
@ -0,0 +1,14 @@
|
||||
import { tick } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
// Tests that a store subscription only present in the template waits for the
|
||||
// promise that assigns the store instead of subscribing to `undefined`,
|
||||
// including when the subscription is read through a function.
|
||||
export default test({
|
||||
mode: ['client', 'hydrate', 'async-server'],
|
||||
ssrHtml: '<p>hello</p> <p>hello</p>',
|
||||
async test({ assert, target }) {
|
||||
await tick();
|
||||
assert.htmlEqual(target.innerHTML, '<p>hello</p> <p>hello</p>');
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,16 @@
|
||||
<script>
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
async function get_store() {
|
||||
return writable('hello');
|
||||
}
|
||||
|
||||
const store = await get_store();
|
||||
|
||||
function read() {
|
||||
return $store;
|
||||
}
|
||||
</script>
|
||||
|
||||
<p>{$store}</p>
|
||||
<p>{read()}</p>
|
||||
@ -0,0 +1,18 @@
|
||||
import { test } from '../../test';
|
||||
import { counts, reset } from './store.js';
|
||||
|
||||
// A blocked store subscription is created after the synchronous part of the
|
||||
// render has finished, so the teardown must wait for the async work.
|
||||
export default test({
|
||||
mode: ['async-server'],
|
||||
|
||||
before_test() {
|
||||
reset();
|
||||
},
|
||||
|
||||
ssrHtml: '<p>hello</p>',
|
||||
|
||||
test_ssr({ assert }) {
|
||||
assert.deepEqual(counts, { subscribes: 1, unsubscribes: 1 });
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,11 @@
|
||||
<script>
|
||||
import { store } from './store.js';
|
||||
|
||||
async function get_store() {
|
||||
return store;
|
||||
}
|
||||
|
||||
const s = await get_store();
|
||||
</script>
|
||||
|
||||
<p>{$s}</p>
|
||||
@ -0,0 +1,23 @@
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
export const counts = { subscribes: 0, unsubscribes: 0 };
|
||||
|
||||
const inner = writable('hello');
|
||||
|
||||
export const store = {
|
||||
/** @param {(value: string) => void} fn */
|
||||
subscribe(fn) {
|
||||
counts.subscribes += 1;
|
||||
const unsubscribe = inner.subscribe(fn);
|
||||
|
||||
return () => {
|
||||
counts.unsubscribes += 1;
|
||||
unsubscribe();
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export function reset() {
|
||||
counts.subscribes = 0;
|
||||
counts.unsubscribes = 0;
|
||||
}
|
||||
Loading…
Reference in new issue