Merge remote-tracking branch 'origin/main' into svelte-custom-renderer

pull/18058/head
paoloricciuti 5 months ago
commit 5456125bab

@ -1,5 +0,0 @@
---
'svelte': patch
---
fix: prevent hydration error on async `{@html ...}`

@ -396,7 +396,7 @@ Invalid selector
### declaration_duplicate_module_import ### declaration_duplicate_module_import
``` ```
Cannot declare a variable with the same name as an import inside `<script module>` Cannot declare a variable with the same name as an import from `<script module>`
``` ```
### derived_invalid_export ### derived_invalid_export

@ -1,5 +1,19 @@
# svelte # svelte
## 5.55.1
### Patch Changes
- fix: correctly handle bindings on the server ([#18009](https://github.com/sveltejs/svelte/pull/18009))
- fix: prevent hydration error on async `{@html ...}` ([#17999](https://github.com/sveltejs/svelte/pull/17999))
- fix: cleanup `superTypeParameters` in `ClassDeclarations`/`ClassExpression` ([#18015](https://github.com/sveltejs/svelte/pull/18015))
- fix: improve duplicate module import error message ([#18016](https://github.com/sveltejs/svelte/pull/18016))
- fix: reschedule new effects in prior batches ([#18021](https://github.com/sveltejs/svelte/pull/18021))
## 5.55.0 ## 5.55.0
### Minor Changes ### Minor Changes

@ -16,7 +16,7 @@
## declaration_duplicate_module_import ## declaration_duplicate_module_import
> Cannot declare a variable with the same name as an import inside `<script module>` > Cannot declare a variable with the same name as an import from `<script module>`
## derived_invalid_export ## derived_invalid_export

@ -2,7 +2,7 @@
"name": "svelte", "name": "svelte",
"description": "Cybernetically enhanced web apps", "description": "Cybernetically enhanced web apps",
"license": "MIT", "license": "MIT",
"version": "5.55.0", "version": "5.55.1",
"type": "module", "type": "module",
"types": "./types/index.d.ts", "types": "./types/index.d.ts",
"engines": { "engines": {
@ -182,7 +182,7 @@
"clsx": "^2.1.1", "clsx": "^2.1.1",
"devalue": "^5.6.4", "devalue": "^5.6.4",
"esm-env": "^1.2.1", "esm-env": "^1.2.1",
"esrap": "^2.2.2", "esrap": "^2.2.4",
"is-reference": "^3.0.3", "is-reference": "^3.0.3",
"locate-character": "^3.0.0", "locate-character": "^3.0.0",
"magic-string": "^0.30.11", "magic-string": "^0.30.11",

@ -117,12 +117,12 @@ export function declaration_duplicate(node, name) {
} }
/** /**
* Cannot declare a variable with the same name as an import inside `<script module>` * Cannot declare a variable with the same name as an import from `<script module>`
* @param {null | number | NodeLike} node * @param {null | number | NodeLike} node
* @returns {never} * @returns {never}
*/ */
export function declaration_duplicate_module_import(node) { export function declaration_duplicate_module_import(node) {
e(node, 'declaration_duplicate_module_import', `Cannot declare a variable with the same name as an import inside \`<script module>\`\nhttps://svelte.dev/e/declaration_duplicate_module_import`); e(node, 'declaration_duplicate_module_import', `Cannot declare a variable with the same name as an import from \`<script module>\`\nhttps://svelte.dev/e/declaration_duplicate_module_import`);
} }
/** /**

@ -138,11 +138,13 @@ const visitors = {
delete node.abstract; delete node.abstract;
delete node.implements; delete node.implements;
delete node.superTypeArguments; delete node.superTypeArguments;
delete node.superTypeParameters;
return context.next(); return context.next();
}, },
ClassExpression(node, context) { ClassExpression(node, context) {
delete node.implements; delete node.implements;
delete node.superTypeArguments; delete node.superTypeArguments;
delete node.superTypeParameters;
return context.next(); return context.next();
}, },
MethodDefinition(node, context) { MethodDefinition(node, context) {

@ -161,7 +161,6 @@ export function ensure_no_module_import_conflict(node, state) {
state.scope === state.analysis.instance.scope && state.scope === state.analysis.instance.scope &&
state.analysis.module.scope.get(id.name)?.declaration_kind === 'import' state.analysis.module.scope.get(id.name)?.declaration_kind === 'import'
) { ) {
// TODO fix the message here
e.declaration_duplicate_module_import(node.id); e.declaration_duplicate_module_import(node.id);
} }
} }

@ -145,6 +145,12 @@ export class Batch {
*/ */
#roots = []; #roots = [];
/**
* Effects created while this batch was active.
* @type {Effect[]}
*/
#new_effects = [];
/** /**
* Deferred effects (which run after async work has completed) that are DIRTY * Deferred effects (which run after async work has completed) that are DIRTY
* @type {Set<Effect>} * @type {Set<Effect>}
@ -472,6 +478,13 @@ export class Batch {
batches.delete(this); batches.delete(this);
} }
/**
* @param {Effect} effect
*/
register_created_effect(effect) {
this.#new_effects.push(effect);
}
#commit() { #commit() {
// If there are other pending batches, they now need to be 'rebased' — // If there are other pending batches, they now need to be 'rebased' —
// in other words, we re-run block/async effects with the newly // in other words, we re-run block/async effects with the newly
@ -525,6 +538,25 @@ export class Batch {
mark_effects(source, others, marked, checked); mark_effects(source, others, marked, checked);
} }
checked = new Map();
var current_unequal = [...batch.current.keys()].filter((c) =>
this.current.has(c) ? /** @type {[any, boolean]} */ (this.current.get(c))[0] !== c : true
);
for (const effect of this.#new_effects) {
if (
(effect.f & (DESTROYED | INERT | EAGER_EFFECT)) === 0 &&
depends_on(effect, current_unequal, checked)
) {
if ((effect.f & (ASYNC | BLOCK_EFFECT)) !== 0) {
set_signal_status(effect, DIRTY);
batch.schedule(effect);
} else {
batch.#dirty_effects.add(effect);
}
}
}
// Only apply and traverse when we know we triggered async work with marking the effects // Only apply and traverse when we know we triggered async work with marking the effects
if (batch.#roots.length > 0) { if (batch.#roots.length > 0) {
batch.apply(); batch.apply();

@ -42,7 +42,7 @@ import { DEV } from 'esm-env';
import { define_property } from '../../shared/utils.js'; import { define_property } from '../../shared/utils.js';
import { get_next_sibling, remove_node, append_child } from '../dom/operations.js'; import { get_next_sibling, remove_node, append_child } from '../dom/operations.js';
import { component_context, dev_current_component_function, dev_stack } from '../context.js'; import { component_context, dev_current_component_function, dev_stack } from '../context.js';
import { Batch, collected_effects } from './batch.js'; import { Batch, collected_effects, current_batch } from './batch.js';
import { flatten, increment_pending } from './async.js'; import { flatten, increment_pending } from './async.js';
import { without_reactive_context } from '../dom/elements/bindings/shared.js'; import { without_reactive_context } from '../dom/elements/bindings/shared.js';
import { set_signal_status } from './status.js'; import { set_signal_status } from './status.js';
@ -122,6 +122,8 @@ function create_effect(type, fn) {
effect.component_function = dev_current_component_function; effect.component_function = dev_current_component_function;
} }
current_batch?.register_created_effect(effect);
/** @type {Effect | null} */ /** @type {Effect | null} */
var e = effect; var e = effect;

@ -468,10 +468,14 @@ export class Renderer {
} }
this.local = other.local; this.local = other.local;
this.#out = other.#out.map((item) => { this.#out = other.#out.map((item, i) => {
if (item instanceof Renderer) { const current = this.#out[i];
item.subsume(item);
if (current instanceof Renderer && item instanceof Renderer) {
current.subsume(item);
return current;
} }
return item; return item;
}); });
this.promise = other.promise; this.promise = other.promise;

@ -4,5 +4,5 @@
* The current version, as set in package.json. * The current version, as set in package.json.
* @type {string} * @type {string}
*/ */
export const VERSION = '5.55.0'; export const VERSION = '5.55.1';
export const PUBLIC_VERSION = '5'; export const PUBLIC_VERSION = '5';

@ -0,0 +1,7 @@
<script>
let data = $derived(await Promise.resolve('test'));
</script>
<div data-resolved={data ? 'true' : 'false'}>
{data}
</div>

@ -0,0 +1,7 @@
<script>
import Bound from './Bound.svelte';
let open;
</script>
<Bound bind:open />

@ -0,0 +1,10 @@
import { test } from '../../test';
// Tests that renderer.subsume (which is used when bindings are present) works correctly
export default test({
mode: ['hydrate'],
html: '<div data-resolved="true">test</div>',
async test({ assert, warnings }) {
assert.deepEqual(warnings, []);
}
});

@ -0,0 +1,7 @@
<script lang="ts">
import Async from './Async.svelte';
import Binding from './Binding.svelte';
</script>
<Async />
<Binding />

@ -2,7 +2,6 @@ import { tick } from 'svelte';
import { test } from '../../test'; import { test } from '../../test';
export default test({ export default test({
skip: true, // TODO works on https://github.com/sveltejs/svelte/pull/17971
async test({ assert, target, logs }) { async test({ assert, target, logs }) {
const [x, y, resolve] = target.querySelectorAll('button'); const [x, y, resolve] = target.querySelectorAll('button');
@ -17,12 +16,20 @@ export default test({
<button>x</button> <button>x</button>
<button>y++</button> <button>y++</button>
<button>resolve</button> <button>resolve</button>
` // if this shows world world - that would also be ok world
` // if this does not show world - that would also be ok
); );
resolve.click(); resolve.click();
await tick(); await tick();
assert.deepEqual(logs, ['universe', 'universe', '$effect: universe', '$effect: universe']); assert.deepEqual(logs, [
'universe',
'world',
'$effect: world',
'$effect: universe',
'$effect: universe'
]);
// assert.deepEqual(logs, ['universe', 'universe', '$effect: universe', '$effect: universe']); // this would also be ok
assert.htmlEqual( assert.htmlEqual(
target.innerHTML, target.innerHTML,
` `

@ -2,7 +2,6 @@ import { tick } from 'svelte';
import { test } from '../../test'; import { test } from '../../test';
export default test({ export default test({
skip: true, // TODO works on https://github.com/sveltejs/svelte/pull/17971
async test({ assert, target }) { async test({ assert, target }) {
const [x, y, resolve] = target.querySelectorAll('button'); const [x, y, resolve] = target.querySelectorAll('button');
@ -18,7 +17,13 @@ export default test({
<button>y++</button> <button>y++</button>
<button>resolve</button> <button>resolve</button>
<hr> <hr>
` // if this shows world world "world" world world world "world" - then this would also be ok world
"world"
world
world
world
"world"
` // if this does not show world "world" world world world "world" - then this would also be ok
); );
resolve.click(); resolve.click();

@ -2,7 +2,6 @@ import { tick } from 'svelte';
import { test } from '../../test'; import { test } from '../../test';
export default test({ export default test({
skip: true, // TODO works on https://github.com/sveltejs/svelte/pull/17971
async test({ assert, target }) { async test({ assert, target }) {
const [x, y, resolve] = target.querySelectorAll('button'); const [x, y, resolve] = target.querySelectorAll('button');
@ -30,9 +29,17 @@ export default test({
<button>y++</button> <button>y++</button>
<button>resolve</button> <button>resolve</button>
<hr> <hr>
` // if this shows world world "world" world world world "world" - then this would also be ok world
"world"
world
world
world
"world"
` // if this does not show world "world" world world world "world" - then this would also be ok
); );
resolve.click();
await tick();
resolve.click(); resolve.click();
await tick(); await tick();
assert.htmlEqual( assert.htmlEqual(

@ -31,4 +31,3 @@
{#if y > 0} {#if y > 0}
<Child x={await delay2(x)} /> <Child x={await delay2(x)} />
{/if} {/if}

@ -2,7 +2,6 @@ import { tick } from 'svelte';
import { test } from '../../test'; import { test } from '../../test';
export default test({ export default test({
skip: true, // TODO works on https://github.com/sveltejs/svelte/pull/17971
async test({ assert, target }) { async test({ assert, target }) {
const [x, y, shift, pop, commit] = target.querySelectorAll('button'); const [x, y, shift, pop, commit] = target.querySelectorAll('button');
@ -43,6 +42,8 @@ export default test({
await tick(); await tick();
shift.click(); shift.click();
await tick(); await tick();
shift.click(); // would be ok to not need this one
await tick();
assert.htmlEqual( assert.htmlEqual(
target.innerHTML, target.innerHTML,
` `

@ -2,7 +2,6 @@ import { tick } from 'svelte';
import { test } from '../../test'; import { test } from '../../test';
export default test({ export default test({
skip: true, // TODO works on https://github.com/sveltejs/svelte/pull/17971
async test({ assert, target }) { async test({ assert, target }) {
const [x, y, resolve, commit] = target.querySelectorAll('button'); const [x, y, resolve, commit] = target.querySelectorAll('button');

@ -2,7 +2,6 @@ import { tick } from 'svelte';
import { test } from '../../test'; import { test } from '../../test';
export default test({ export default test({
skip: true, // this fails on main, too; skip for now
async test({ assert, target, logs }) { async test({ assert, target, logs }) {
const [x, y, resolve] = target.querySelectorAll('button'); const [x, y, resolve] = target.querySelectorAll('button');

@ -27,6 +27,11 @@
abstract x(): void; abstract x(): void;
y() {} y() {}
} }
class Subclass extends Foo<string> {
constructor(value: string) {
super(value);
}
}
declare const declared_const: number; declare const declared_const: number;
declare function declared_fn(): void; declare function declared_fn(): void;

@ -1,7 +1,7 @@
[ [
{ {
"code": "declaration_duplicate_module_import", "code": "declaration_duplicate_module_import",
"message": "Cannot declare a variable with the same name as an import inside `<script module>`", "message": "Cannot declare a variable with the same name as an import from `<script module>`",
"start": { "start": {
"line": 12, "line": 12,
"column": 5 "column": 5

@ -102,8 +102,8 @@ importers:
specifier: ^1.2.1 specifier: ^1.2.1
version: 1.2.1 version: 1.2.1
esrap: esrap:
specifier: ^2.2.2 specifier: ^2.2.4
version: 2.2.2 version: 2.2.4
is-reference: is-reference:
specifier: ^3.0.3 specifier: ^3.0.3
version: 3.0.3 version: 3.0.3
@ -1418,8 +1418,8 @@ packages:
resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==}
engines: {node: '>=0.10'} engines: {node: '>=0.10'}
esrap@2.2.2: esrap@2.2.4:
resolution: {integrity: sha512-zA6497ha+qKvoWIK+WM9NAh5ni17sKZKhbS5B3PoYbBvaYHZWoS33zmFybmyqpn07RLUxSmn+RCls2/XF+d0oQ==} resolution: {integrity: sha512-suICpxAmZ9A8bzJjEl/+rLJiDKC0X4gYWUxT6URAWBLvlXmtbZd5ySMu/N2ZGEtMCAmflUDPSehrP9BQcsGcSg==}
esrecurse@4.3.0: esrecurse@4.3.0:
resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
@ -3794,9 +3794,10 @@ snapshots:
dependencies: dependencies:
estraverse: 5.3.0 estraverse: 5.3.0
esrap@2.2.2: esrap@2.2.4:
dependencies: dependencies:
'@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/sourcemap-codec': 1.5.0
'@typescript-eslint/types': 8.56.0
esrecurse@4.3.0: esrecurse@4.3.0:
dependencies: dependencies:

Loading…
Cancel
Save