Merge branch 'main' into fix-memory-leak-

fix-memory-leak-
Dominic Gannaway 1 year ago
commit 4167765a9d

@ -0,0 +1,5 @@
---
"svelte": patch
---
fix: set correct scope for `@const` tags within slots

@ -0,0 +1,5 @@
---
"svelte": patch
---
fix: better support for onwheel events in chrome

@ -0,0 +1,5 @@
---
"svelte": patch
---
fix: coherent infinite loop guard

@ -31,6 +31,8 @@ jobs:
steps:
- uses: actions/checkout@v3
- uses: pnpm/action-setup@v2.2.4
with:
version: 9
- uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
@ -46,6 +48,8 @@ jobs:
steps:
- uses: actions/checkout@v3
- uses: pnpm/action-setup@v2.2.4
with:
version: 9
- uses: actions/setup-node@v3
with:
node-version: 18

@ -22,6 +22,8 @@ jobs:
# This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits
fetch-depth: 0
- uses: pnpm/action-setup@v2.2.4
with:
version: 9
- name: Setup Node.js
uses: actions/setup-node@v3
with:

@ -5,9 +5,8 @@
"private": true,
"type": "module",
"license": "MIT",
"packageManager": "pnpm@8.6.12",
"engines": {
"pnpm": "^8.0.0"
"pnpm": "^9.0.0"
},
"repository": {
"type": "git",

@ -847,7 +847,13 @@ function serialize_inline_component(node, component_name, context) {
/** @type {import('estree').Property[]} */
const serialized_slots = [];
for (const slot_name of Object.keys(children)) {
const body = create_block(node, `${node.name}_${slot_name}`, children[slot_name], context);
const body = create_block(
node,
node.fragment,
`${node.name}_${slot_name}`,
children[slot_name],
context
);
if (body.length === 0) continue;
const slot_fn = b.arrow(
@ -1023,13 +1029,14 @@ function serialize_locations(locations) {
* ```
* Adds the hoisted parts to `context.state.hoisted` and returns the statements of the main block.
* @param {import('#compiler').SvelteNode} parent
* @param {import('#compiler').Fragment} fragment
* @param {string} name
* @param {import('#compiler').SvelteNode[]} nodes
* @param {import('../types.js').ComponentContext} context
* @returns {import('estree').Statement[]}
*/
function create_block(parent, name, nodes, context) {
const namespace = infer_namespace(context.state.metadata.namespace, parent, nodes, context.path);
function create_block(parent, fragment, name, nodes, context) {
const namespace = infer_namespace(context.state.metadata.namespace, parent, nodes);
const { hoisted, trimmed } = clean_nodes(
parent,
@ -1060,6 +1067,7 @@ function create_block(parent, name, nodes, context) {
/** @type {import('../types').ComponentClientTransformState} */
const state = {
...context.state,
scope: context.state.scopes.get(fragment) ?? context.state.scope,
before_init: [],
init: [],
update: [],
@ -1616,7 +1624,7 @@ function serialize_attribute_value(attribute_value, context) {
/**
* @param {Array<import('#compiler').Text | import('#compiler').ExpressionTag>} values
* @param {(node: import('#compiler').SvelteNode) => any} visit
* @param {(node: import('#compiler').SvelteNode, state: any) => any} visit
* @param {import("../types.js").ComponentClientTransformState} state
* @returns {[boolean, import('estree').TemplateLiteral]}
*/
@ -1661,13 +1669,13 @@ function serialize_template_literal(values, visit, state) {
id,
create_derived(
state,
b.thunk(/** @type {import('estree').Expression} */ (visit(node.expression)))
b.thunk(/** @type {import('estree').Expression} */ (visit(node.expression, state)))
)
)
);
expressions.push(b.call('$.get', id));
} else {
expressions.push(b.call('$.stringify', visit(node.expression)));
expressions.push(b.call('$.stringify', visit(node.expression, state)));
}
quasis.push(b.quasi('', i + 1 === values.length));
}
@ -1680,7 +1688,7 @@ function serialize_template_literal(values, visit, state) {
/** @type {import('../types').ComponentVisitors} */
export const template_visitors = {
Fragment(node, context) {
const body = create_block(node, 'root', node.nodes, context);
const body = create_block(context.path.at(-1) ?? node, node, 'root', node.nodes, context);
return b.block(body);
},
Comment(node, context) {
@ -2221,7 +2229,7 @@ export const template_visitors = {
}
inner.push(...inner_context.state.after_update);
inner.push(
...create_block(node, 'dynamic_element', node.fragment.nodes, {
...create_block(node, node.fragment, 'dynamic_element', node.fragment.nodes, {
...context,
state: {
...context.state,
@ -2449,7 +2457,7 @@ export const template_visitors = {
}
// TODO should use context.visit?
const children = create_block(node, 'each_block', node.body.nodes, context);
const children = create_block(node, node.body, 'each_block', node.body.nodes, context);
const key_function = node.key
? b.arrow(
@ -3017,22 +3025,14 @@ export const template_visitors = {
}
}
const state = {
...context.state,
// TODO this logic eventually belongs in create_block, when fragments are used everywhere
scope: /** @type {import('../../../scope').Scope} */ (context.state.scopes.get(node.fragment))
};
context.state.init.push(...lets);
context.state.init.push(
...create_block(
node,
node.fragment,
'slot_template',
/** @type {import('#compiler').SvelteNode[]} */ (node.fragment.nodes),
{
...context,
state
}
context
)
);
},
@ -3088,7 +3088,7 @@ export const template_visitors = {
? b.literal(null)
: b.arrow(
[b.id('$$anchor')],
b.block(create_block(node, 'fallback', node.fragment.nodes, context))
b.block(create_block(node, node.fragment, 'fallback', node.fragment.nodes, context))
);
const expression = is_default
@ -3106,7 +3106,7 @@ export const template_visitors = {
'$.head',
b.arrow(
[b.id('$$anchor')],
b.block(create_block(node, 'head', node.fragment.nodes, context))
b.block(create_block(node, node.fragment, 'head', node.fragment.nodes, context))
)
)
)

@ -240,13 +240,14 @@ function process_children(nodes, parent, { visit, state }) {
/**
* @param {import('#compiler').SvelteNode} parent
* @param {import('#compiler').Fragment} fragment
* @param {import('#compiler').SvelteNode[]} nodes
* @param {import('./types').ComponentContext} context
* @param {import('./types').Anchor} [anchor]
* @returns {import('estree').Statement[]}
*/
function create_block(parent, nodes, context, anchor) {
const namespace = infer_namespace(context.state.metadata.namespace, parent, nodes, context.path);
function create_block(parent, fragment, nodes, context, anchor) {
const namespace = infer_namespace(context.state.metadata.namespace, parent, nodes);
const { hoisted, trimmed } = clean_nodes(
parent,
@ -264,6 +265,7 @@ function create_block(parent, nodes, context, anchor) {
/** @type {import('./types').ComponentServerTransformState} */
const state = {
...context.state,
scope: context.state.scopes.get(fragment) ?? context.state.scope,
init: [],
template: [],
metadata: {
@ -1085,7 +1087,7 @@ function serialize_inline_component(node, component_name, context) {
const serialized_slots = [];
for (const slot_name of Object.keys(children)) {
const body = create_block(node, children[slot_name], context);
const body = create_block(node, node.fragment, children[slot_name], context);
if (body.length === 0) continue;
const slot_fn = b.arrow(
@ -1268,7 +1270,7 @@ const javascript_visitors_legacy = {
/** @type {import('./types').ComponentVisitors} */
const template_visitors = {
Fragment(node, context) {
const body = create_block(node, node.nodes, context);
const body = create_block(context.path.at(-1) ?? node, node, node.nodes, context);
return b.block(body);
},
HtmlTag(node, context) {
@ -1472,7 +1474,7 @@ const template_visitors = {
context.state.template.push(block_open);
const main = create_block(node, node.fragment.nodes, {
const main = create_block(node, node.fragment, node.fragment.nodes, {
...context,
state: { ...context.state, metadata }
});
@ -1541,7 +1543,9 @@ const template_visitors = {
each.push(b.stmt(b.assignment('+=', b.id('$$payload.out'), b.literal(block_open.value))));
each.push(
.../** @type {import('estree').Statement[]} */ (create_block(node, children, context))
.../** @type {import('estree').Statement[]} */ (
create_block(node, node.body, children, context)
)
);
each.push(b.stmt(b.assignment('+=', b.id('$$payload.out'), b.literal(block_close.value))));
@ -1556,7 +1560,7 @@ const template_visitors = {
const close = b.stmt(b.assignment('+=', b.id('$$payload.out'), b.literal(BLOCK_CLOSE)));
if (node.fallback) {
const fallback = create_block(node, node.fallback.nodes, context);
const fallback = create_block(node, node.fallback, node.fallback.nodes, context);
fallback.push(b.stmt(b.assignment('+=', b.id('$$payload.out'), b.literal(BLOCK_CLOSE_ELSE))));
@ -1577,8 +1581,10 @@ const template_visitors = {
const state = context.state;
state.template.push(block_open);
const consequent = create_block(node, node.consequent.nodes, context);
const alternate = node.alternate ? create_block(node, node.alternate.nodes, context) : [];
const consequent = create_block(node, node.consequent, node.consequent.nodes, context);
const alternate = node.alternate
? create_block(node, node.alternate, node.alternate.nodes, context)
: [];
consequent.push(b.stmt(b.assignment('+=', b.id('$$payload.out'), b.literal(BLOCK_CLOSE))));
alternate.push(b.stmt(b.assignment('+=', b.id('$$payload.out'), b.literal(BLOCK_CLOSE_ELSE))));
@ -1634,7 +1640,7 @@ const template_visitors = {
KeyBlock(node, context) {
const state = context.state;
state.template.push(block_open);
const body = create_block(node, node.fragment.nodes, context);
const body = create_block(node, node.fragment, node.fragment.nodes, context);
state.template.push(t_statement(b.block(body)));
state.template.push(block_close);
},
@ -1724,15 +1730,7 @@ const template_visitors = {
}
}
const state = {
...context.state,
// TODO this logic eventually belongs in create_block, when fragments are used everywhere
scope: /** @type {import('../../scope').Scope} */ (context.state.scopes.get(node.fragment))
};
const body = create_block(node, node.fragment.nodes, {
...context,
state
});
const body = create_block(node, node.fragment, node.fragment.nodes, context);
context.state.template.push(t_statement(b.block(body)));
},
@ -1802,7 +1800,7 @@ const template_visitors = {
const fallback =
node.fragment.nodes.length === 0
? b.literal(null)
: b.thunk(b.block(create_block(node, node.fragment.nodes, context)));
: b.thunk(b.block(create_block(node, node.fragment, node.fragment.nodes, context)));
const slot = b.call('$.slot', b.id('$$payload'), expression, props_expression, fallback);
state.template.push(t_statement(b.stmt(slot)));
@ -1810,7 +1808,7 @@ const template_visitors = {
},
SvelteHead(node, context) {
const state = context.state;
const body = create_block(node, node.fragment.nodes, context);
const body = create_block(node, node.fragment, node.fragment.nodes, context);
state.template.push(
t_statement(
b.stmt(b.call('$.head', b.id('$$payload'), b.arrow([b.id('$$payload')], b.block(body))))

@ -155,35 +155,28 @@ export function clean_nodes(
* @param {import('#compiler').Namespace} namespace
* @param {import('#compiler').SvelteNode} parent
* @param {import('#compiler').SvelteNode[]} nodes
* @param {import('#compiler').SvelteNode[]} path
*/
export function infer_namespace(namespace, parent, nodes, path) {
const parent_node =
parent.type === 'Fragment'
? // Messy: We know that Fragment calls create_block directly, so we can do this here
path.at(-1)
: parent;
export function infer_namespace(namespace, parent, nodes) {
if (namespace !== 'foreign') {
if (parent_node?.type === 'RegularElement' && parent_node.name === 'foreignObject') {
if (parent.type === 'RegularElement' && parent.name === 'foreignObject') {
return 'html';
}
if (parent_node?.type === 'RegularElement' || parent_node?.type === 'SvelteElement') {
if (parent_node.metadata.svg) {
if (parent.type === 'RegularElement' || parent.type === 'SvelteElement') {
if (parent.metadata.svg) {
return 'svg';
}
return parent_node.metadata.mathml ? 'mathml' : 'html';
return parent.metadata.mathml ? 'mathml' : 'html';
}
// Re-evaluate the namespace inside slot nodes that reset the namespace
if (
parent_node === undefined ||
parent_node.type === 'Root' ||
parent_node.type === 'Component' ||
parent_node.type === 'SvelteComponent' ||
parent_node.type === 'SvelteFragment' ||
parent_node.type === 'SnippetBlock'
parent.type === 'Fragment' ||
parent.type === 'Root' ||
parent.type === 'Component' ||
parent.type === 'SvelteComponent' ||
parent.type === 'SvelteFragment' ||
parent.type === 'SnippetBlock'
) {
const new_namespace = check_nodes_for_namespace(nodes, 'keep');
if (new_namespace !== 'keep' && new_namespace !== 'maybe_html') {

@ -280,8 +280,6 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) {
next({ scope });
};
const skip = () => {};
/**
* @type {import('zimmerframe').Visitor<import('#compiler').ElementLike, State, import('#compiler').SvelteNode>}
*/

@ -55,8 +55,8 @@ export function create_event(event_name, dom, handler, options) {
// Chrome has a bug where pointer events don't work when attached to a DOM element that has been cloned
// with cloneNode() and the DOM element is disconnected from the document. To ensure the event works, we
// defer the attachment till after it's been appended to the document. TODO: remove this once Chrome fixes
// this bug.
if (event_name.startsWith('pointer')) {
// this bug. The same applies to wheel events.
if (event_name.startsWith('pointer') || event_name === 'wheel') {
queue_micro_task(() => {
dom.addEventListener(event_name, target_handler, options);
});

@ -591,7 +591,7 @@ function flush_queued_effects(effects) {
function process_deferred() {
is_micro_task_queued = false;
is_yield_task_queued = false;
if (flush_count > 101) {
if (flush_count > 1001) {
return;
}
const previous_queued_root_effects = current_queued_root_effects;

@ -0,0 +1,7 @@
import { test } from '../../test';
export default test({
html: `
<div slot="footer">hello hello</div>
`
});

@ -0,0 +1,13 @@
<script>
import Nested from "./Nested.svelte"
import Nested2 from "./Nested2.svelte"
</script>
<Nested>
<Nested2 slot="inner" let:text>
<div slot="footer">
{@const text2 = text}
{text} {text2}
</div>
</Nested2>
</Nested>

File diff suppressed because it is too large Load Diff

@ -39,7 +39,7 @@ Traditional `on:` event handlers will continue to work, but are deprecated in Sv
In Svelte 4, components could emit events by creating a dispatcher with [`createEventDispatcher`](https://svelte.dev/docs/svelte#createeventdispatcher).
This function is deprecated in Svelte 5. Instead, components should accept _callback props_ ([demo](/#H4sIAAAAAAAAE41TS27bMBC9ykBtELu1ZTmAG0C2hPYG3dddyPIwJkKRAjmy4wrad9VFL5BV75cjlKQof5osutCHb968-XCmjRgXaKL0WxvJosIojb7UdTSJ6Fi7g9mjILRnoxpdOmRlSs1rytdyTbyqlSb42lQ1MK0quI1n7hD3brdLR3KPQALDfyBk8N5QQTiaL8bLwbJptKGziRXCoLdaO2tkSVxJ0GiQRmNovSYFtfmij0GDhnf2WLeWq9k5WblymfmsJRM2TtZatSy_EvyYwSDIGYw8lsP9YnzKkXQT5Dv33uJbWhe-ybgvfDooO7-ZT6h9Z3le10utNg2RLVTJUvDyMWt9xV0u8QCbQgilbD09xzd_ZepCQikKY7J1tFGqWkf5y_PvP7Zqa7GcNkXbjO4Nci-3jsDQUaBFTFkITKFN4mQOH3zKnZXry3l5_vXTi5yEZ5x1vqfe39N8gFB_rQx3l5YC40-4DR0VyCiFJJxI1efDgW9pl8I8SW4CskP-sKMriClJU5eZR_eHQQifaFoI_mDDlSgJ9RCPS5yedJZDatxRpri3VJOCVPI0Lu4Th94MpZAu5FCMbxIk8Z259rCtH-iF5FXRsz2cxAsDTOlDobdXXp8f8ci03TgDl_7JDbQQLiOJP0HXw3eLK_x-MRhcey4sPdxPfrgZu7uV2nLGcRulbnq7yWnV3Ub87667RW0h7M4EwuBD5_a21qo2I7ey1xv370QH7y4PPxfz_IobAnR5-DlxXxf0vfsLb_4Z08cEAAA=)):
This function is deprecated in Svelte 5. Instead, components should accept _callback props_ - which means you then pass functions as properties to these components ([demo](/#H4sIAAAAAAAACo1US27bMBC9yoBtELu2ZDmAG0CRhPYG3VddyPIwIUKRgjiOkwrcd9VFL5BV75cjFKQo2e5_IQnzeW-GM3zqGRcSDUs_9kxVDbKUvW9btmT01DrDPKAkZEtm9L6rnSczdSdaKkpVkmha3RF82Dct8E43cBmvnBEPsMsbl-QeiQRGfEbI4bWhinC23sxvxsh23xk6hnglDfqoKonvVU1CK-jQIM3m0HtOCmzrzVCDRg4P9j5bqmx1bFZlrjPfteKyIsz7WasP2M0hL85YFzn4QGAWHGbeX8D1Zj41S90-1LHuvcM_kp4QJPNhDNFpCUew8i32rwQfCnjObLsn0gq0qqWo7_Pez8AWCg-wraTUWmWrIcevIzNtpaCWlTF5ybZaNyUrXp6_fc9WLlKUqk9RGrS_SR7oSgaGniTmJTN1JTGFPomTNbzxbduSFcORXp6_fvEkE_FKcOun7PE-zRcIM2i1EW6NKXDxiLswWomcUkiCRbo9Ggexo7sU1klyETx3KG7v6MzFtaLIdea9D4eRCB8pqqS4VSnUqGhapRQKo4nnZmxNuJQIH1CRSUFpNV0g94nDbMajUFep8TB-SJDEV-YcoXUzpldKNNWQ7d1JvDHAdXeout0Z6t09PvGuatDAKT65gB7CMpL4LdjBfbU5819vxoAbz0lkcA9aCJthS9boneACdyx119guJ_E7jfyv-p10ewhqWkJQAFin5LbTrZkdJe5v-1HiXvzn6vz5rs-8hAJ7EJUtgn1y7f8ADN1MwGD_G-gBUWSLaModfnA-kELvvxb-Bl8sbLGY4L_O-5P9ATwVcA54BQAA)):
```svelte
<script>
@ -55,12 +55,12 @@ This function is deprecated in Svelte 5. Instead, components should accept _call
</script>
<Pump
inflate={() => {
size += 5;
inflate={(power) => {
size += power;
if (size > 75) burst = true;
}}
deflate={() => {
if (size > 0) size -= 5;
deflate={(power) => {
if (size > 0) size -= power;
}}
/>
@ -77,10 +77,14 @@ This function is deprecated in Svelte 5. Instead, components should accept _call
```svelte
<script>
let { inflate, deflate } = $props();
let power = $state(5);
</script>
<button onclick={inflate}>inflate</button>
<button onclick={deflate}>deflate</button>
<button onclick={() => inflate(power)}>inflate</button>
<button onclick={() => deflate(power)}>deflate</button>
<button onclick={() => power--}>-</button>
Pump power: {power}
<button onclick={() => power++}>+</button>
```
## Bubbling events

Loading…
Cancel
Save