Skip to content

Commit 1fc1c53

Browse files
committed
give arrow functions stable id, better code gen
1 parent f73fb4b commit 1fc1c53

File tree

2 files changed

+39
-20
lines changed

2 files changed

+39
-20
lines changed

packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -263,17 +263,28 @@ function serialize_element_spread_attributes(
263263
) {
264264
let needs_isolation = false;
265265

266-
/** @type {import('estree').Expression[]} */
266+
/** @type {import('estree').ObjectExpression['properties']} */
267267
const values = [];
268268

269269
for (const attribute of attributes) {
270270
if (attribute.type === 'Attribute') {
271271
const name = get_attribute_name(element, attribute, context);
272272
// TODO: handle contains_call_expression
273273
const [, value] = serialize_attribute_value(attribute.value, context);
274-
values.push(b.object([b.init(name, value)]));
274+
275+
if (
276+
is_event_attribute(attribute) &&
277+
attribute.value[0].expression.type === 'ArrowFunctionExpression'
278+
) {
279+
// Give the event handler a stable ID so it isn't removed and readded on every update
280+
const id = context.state.scope.generate('event_handler');
281+
context.state.init.push(b.var(id, value));
282+
values.push(b.init(attribute.name, b.id(id)));
283+
} else {
284+
values.push(b.init(name, value));
285+
}
275286
} else {
276-
values.push(/** @type {import('estree').Expression} */ (context.visit(attribute)));
287+
values.push(b.spread(/** @type {import('estree').Expression} */ (context.visit(attribute))));
277288
}
278289

279290
needs_isolation ||=
@@ -292,7 +303,7 @@ function serialize_element_spread_attributes(
292303
'$.set_attributes',
293304
element_id,
294305
b.id(id),
295-
b.array(values),
306+
b.object(values),
296307
lowercase_attributes,
297308
b.literal(context.state.analysis.css.hash)
298309
)
@@ -350,15 +361,26 @@ function serialize_dynamic_element_attributes(attributes, context, element_id) {
350361
let needs_isolation = false;
351362
let is_reactive = false;
352363

353-
/** @type {import('estree').Expression[]} */
364+
/** @type {import('estree').ObjectExpression['properties']} */
354365
const values = [];
355366

356367
for (const attribute of attributes) {
357368
if (attribute.type === 'Attribute') {
358369
const [, value] = serialize_attribute_value(attribute.value, context);
359-
values.push(b.object([b.init(attribute.name, value)]));
370+
371+
if (
372+
is_event_attribute(attribute) &&
373+
attribute.value[0].expression.type === 'ArrowFunctionExpression'
374+
) {
375+
// Give the event handler a stable ID so it isn't removed and readded on every update
376+
const id = context.state.scope.generate('event_handler');
377+
context.state.init.push(b.var(id, value));
378+
values.push(b.init(attribute.name, b.id(id)));
379+
} else {
380+
values.push(b.init(attribute.name, value));
381+
}
360382
} else {
361-
values.push(/** @type {import('estree').Expression} */ (context.visit(attribute)));
383+
values.push(b.spread(/** @type {import('estree').Expression} */ (context.visit(attribute))));
362384
}
363385

364386
is_reactive ||=
@@ -381,7 +403,7 @@ function serialize_dynamic_element_attributes(attributes, context, element_id) {
381403
'$.set_dynamic_element_attributes',
382404
element_id,
383405
b.id(id),
384-
b.array(values),
406+
b.object(values),
385407
b.literal(context.state.analysis.css.hash)
386408
)
387409
)
@@ -402,7 +424,7 @@ function serialize_dynamic_element_attributes(attributes, context, element_id) {
402424
'$.set_dynamic_element_attributes',
403425
element_id,
404426
b.literal(null),
405-
b.array(values),
427+
b.object(values),
406428
b.literal(context.state.analysis.css.hash)
407429
)
408430
)

packages/svelte/src/internal/client/dom/elements/attributes.js

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,13 @@ export function set_custom_element_data(node, prop, value) {
8383
/**
8484
* Spreads attributes onto a DOM element, taking into account the currently set attributes
8585
* @param {Element & ElementCSSInlineStyle} element
86-
* @param {Record<string, unknown> | undefined} prev
87-
* @param {Record<string, unknown>[]} attrs
86+
* @param {Record<string, any> | undefined} prev
87+
* @param {Record<string, any>} next New attributes - this function mutates this object
8888
* @param {boolean} lowercase_attributes
8989
* @param {string} css_hash
90-
* @returns {Record<string, unknown>}
90+
* @returns {Record<string, any>}
9191
*/
92-
export function set_attributes(element, prev, attrs, lowercase_attributes, css_hash) {
93-
var next = object_assign({}, ...attrs);
92+
export function set_attributes(element, prev, next, lowercase_attributes, css_hash) {
9493
var has_hash = css_hash.length !== 0;
9594

9695
for (var key in prev) {
@@ -196,14 +195,12 @@ export function set_attributes(element, prev, attrs, lowercase_attributes, css_h
196195

197196
/**
198197
* @param {Element} node
199-
* @param {Record<string, unknown> | undefined} prev
200-
* @param {Record<string, unknown>[]} attrs
198+
* @param {Record<string, any> | undefined} prev
199+
* @param {Record<string, any>} next The new attributes - this function mutates this object
201200
* @param {string} css_hash
202201
*/
203-
export function set_dynamic_element_attributes(node, prev, attrs, css_hash) {
202+
export function set_dynamic_element_attributes(node, prev, next, css_hash) {
204203
if (node.tagName.includes('-')) {
205-
var next = object_assign({}, ...attrs);
206-
207204
for (var key in prev) {
208205
if (!(key in next)) {
209206
next[key] = null;
@@ -220,7 +217,7 @@ export function set_dynamic_element_attributes(node, prev, attrs, css_hash) {
220217
return set_attributes(
221218
/** @type {Element & ElementCSSInlineStyle} */ (node),
222219
prev,
223-
attrs,
220+
next,
224221
node.namespaceURI !== namespace_svg,
225222
css_hash
226223
);

0 commit comments

Comments
 (0)