mirror of https://github.com/sveltejs/svelte
commit
ce6e71c695
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'svelte': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: don't (re)connect deriveds when read inside branch/root effects
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'svelte': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: skip unnecessary derived effect in earlier batch
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'svelte': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: avoid declaration tag warning in event handlers
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'svelte': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: transform computed keys in keyed `{#each}` destructuring patterns
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'svelte': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: chain preprocessor sourcemaps with an empty `sources[0]` instead of dropping them
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
import assert from 'node:assert';
|
||||||
|
import * as $ from 'svelte/internal/client';
|
||||||
|
import { block } from '../../../../packages/svelte/src/internal/client/reactivity/effects.js';
|
||||||
|
|
||||||
|
// Like `kairo_broad`, but each derived is also read by a block effect, as
|
||||||
|
// happens with e.g. `{#if derived}` in a component. Measures our #traverse perf better.
|
||||||
|
export default () => {
|
||||||
|
let head = $.state(0);
|
||||||
|
let last = head;
|
||||||
|
let counter = 0;
|
||||||
|
|
||||||
|
const destroy = $.effect_root(() => {
|
||||||
|
for (let i = 0; i < 50; i++) {
|
||||||
|
let current = $.derived(() => {
|
||||||
|
return $.get(head) + i;
|
||||||
|
});
|
||||||
|
let current2 = $.derived(() => {
|
||||||
|
return $.get(current) + 1;
|
||||||
|
});
|
||||||
|
block(() => {
|
||||||
|
$.get(current2);
|
||||||
|
});
|
||||||
|
$.render_effect(() => {
|
||||||
|
$.get(current2);
|
||||||
|
counter++;
|
||||||
|
});
|
||||||
|
last = current2;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
destroy,
|
||||||
|
run() {
|
||||||
|
$.flush(() => {
|
||||||
|
$.set(head, 1);
|
||||||
|
});
|
||||||
|
counter = 0;
|
||||||
|
for (let i = 0; i < 50; i++) {
|
||||||
|
$.flush(() => {
|
||||||
|
$.set(head, i);
|
||||||
|
});
|
||||||
|
assert.equal($.get(last), i + 50);
|
||||||
|
}
|
||||||
|
assert.equal(counter, 50 * 50);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
import assert from 'node:assert';
|
||||||
|
import * as $ from 'svelte/internal/client';
|
||||||
|
import { block } from '../../../../packages/svelte/src/internal/client/reactivity/effects.js';
|
||||||
|
|
||||||
|
let len = 50;
|
||||||
|
const iter = 50;
|
||||||
|
|
||||||
|
// Like `kairo_deep`, but the derived chain is also read by a block effect, as
|
||||||
|
// happens with e.g. `{#if derived}` in a component. Measures our #traverse perf better.
|
||||||
|
export default () => {
|
||||||
|
let head = $.state(0);
|
||||||
|
let current = head;
|
||||||
|
for (let i = 0; i < len; i++) {
|
||||||
|
let c = current;
|
||||||
|
current = $.derived(() => {
|
||||||
|
return $.get(c) + 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let counter = 0;
|
||||||
|
|
||||||
|
const destroy = $.effect_root(() => {
|
||||||
|
block(() => {
|
||||||
|
$.get(current);
|
||||||
|
});
|
||||||
|
|
||||||
|
$.render_effect(() => {
|
||||||
|
$.get(current);
|
||||||
|
counter++;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
destroy,
|
||||||
|
run() {
|
||||||
|
$.flush(() => {
|
||||||
|
$.set(head, 1);
|
||||||
|
});
|
||||||
|
counter = 0;
|
||||||
|
for (let i = 0; i < iter; i++) {
|
||||||
|
$.flush(() => {
|
||||||
|
$.set(head, i);
|
||||||
|
});
|
||||||
|
assert.equal($.get(current), len + i);
|
||||||
|
}
|
||||||
|
assert.equal(counter, iter);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
import { tick } from 'svelte';
|
||||||
|
import { test } from '../../test';
|
||||||
|
|
||||||
|
export default test({
|
||||||
|
async test({ assert, target }) {
|
||||||
|
const [increment, pop] = target.querySelectorAll('button');
|
||||||
|
|
||||||
|
increment.click();
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(
|
||||||
|
target.innerHTML,
|
||||||
|
`<button>increment</button> <button>pop</button> <p>Loading...</p>`
|
||||||
|
);
|
||||||
|
increment.click();
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(
|
||||||
|
target.innerHTML,
|
||||||
|
`<button>increment</button> <button>pop</button> <p>Loading...</p>`
|
||||||
|
);
|
||||||
|
pop.click();
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, `<button>increment</button> <button>pop</button> 2 2 1`);
|
||||||
|
|
||||||
|
pop.click();
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(target.innerHTML, `<button>increment</button> <button>pop</button> 2 2 1`);
|
||||||
|
}
|
||||||
|
});
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
<script>
|
||||||
|
let count = $state(0);
|
||||||
|
let other = $state(0);
|
||||||
|
|
||||||
|
const queue = [];
|
||||||
|
let pending = $derived(defaultPending);
|
||||||
|
function push(v) {
|
||||||
|
return new Promise((resolve) => queue.push(() => resolve(v)));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button onclick={() => {
|
||||||
|
if (count === 0) {
|
||||||
|
other++;
|
||||||
|
count++;
|
||||||
|
} else {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}}>increment</button>
|
||||||
|
<button onclick={() => queue.pop()?.()}>pop</button>
|
||||||
|
{#snippet defaultPending()}
|
||||||
|
<p>Loading...</p>
|
||||||
|
{/snippet}
|
||||||
|
|
||||||
|
{#if count > 0}
|
||||||
|
<svelte:boundary {pending}>
|
||||||
|
{await push(count)} {count} {other}
|
||||||
|
</svelte:boundary>
|
||||||
|
{/if}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
<script>
|
||||||
|
let { labelKey, valueKey, options } = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#each options as { [labelKey]: label, [valueKey]: value } (value)}
|
||||||
|
<p>{label}: {value}</p>
|
||||||
|
{/each}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
import { flushSync } from 'svelte';
|
||||||
|
import { ok, test } from '../../test';
|
||||||
|
|
||||||
|
// https://github.com/sveltejs/svelte/issues/18519
|
||||||
|
export default test({
|
||||||
|
html: `
|
||||||
|
<button>reverse</button>
|
||||||
|
<p>1: a1</p>
|
||||||
|
<p>2: a2</p>
|
||||||
|
<p>3: a3</p>
|
||||||
|
`,
|
||||||
|
|
||||||
|
test({ assert, target }) {
|
||||||
|
const btn = target.querySelector('button');
|
||||||
|
ok(btn);
|
||||||
|
|
||||||
|
flushSync(() => btn.click());
|
||||||
|
|
||||||
|
assert.htmlEqual(
|
||||||
|
target.innerHTML,
|
||||||
|
`
|
||||||
|
<button>reverse</button>
|
||||||
|
<p>3: a3</p>
|
||||||
|
<p>2: a2</p>
|
||||||
|
<p>1: a1</p>
|
||||||
|
`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
<script>
|
||||||
|
import Child from './Child.svelte';
|
||||||
|
|
||||||
|
let options = $state([
|
||||||
|
{ a: 1, v: 'a1' },
|
||||||
|
{ a: 2, v: 'a2' },
|
||||||
|
{ a: 3, v: 'a3' }
|
||||||
|
]);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button onclick={() => options.reverse()}>reverse</button>
|
||||||
|
<Child {options} labelKey="a" valueKey="v" />
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
import * as fs from 'node:fs';
|
||||||
|
import MagicString from 'magic-string';
|
||||||
|
import { test } from '../../test';
|
||||||
|
|
||||||
|
// Simulates a bundler plugin (e.g. a Vite plugin using `magic-string`) that transforms
|
||||||
|
// the Svelte source *before* it reaches `compile()`, and hands its own sourcemap to
|
||||||
|
// `compileOptions.sourcemap` — the documented way to let svelte chain an upstream map
|
||||||
|
// into its own output map. Crucially, the upstream map is generated *without* a `source`
|
||||||
|
// option, exactly like `new MagicString(code).generateMap()` — this yields a sourcemap
|
||||||
|
// whose `sources` is `['']`, which previously broke the chain entirely (see #18491)
|
||||||
|
// instead of being treated as "this file", causing every mapping through it to resolve
|
||||||
|
// to `{ source: null, line: null, column: null }`.
|
||||||
|
const input = fs.readFileSync(new URL('./input.svelte', import.meta.url), 'utf-8');
|
||||||
|
const src = new MagicString(input);
|
||||||
|
src.overwrite(
|
||||||
|
src.original.indexOf('count * 2'),
|
||||||
|
src.original.indexOf('count * 2') + 'count * 2'.length,
|
||||||
|
'count * 2',
|
||||||
|
{
|
||||||
|
storeName: false
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export default test({
|
||||||
|
compileOptions: {
|
||||||
|
sourcemap: src.generateMap({ hires: true })
|
||||||
|
},
|
||||||
|
client: [{ str: 'let doubled' }]
|
||||||
|
});
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
<script>
|
||||||
|
let count = 0;
|
||||||
|
let doubled = count * 2;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button>clicks: {count}</button>
|
||||||
Loading…
Reference in new issue