@@ -289,15 +289,15 @@ function setup_select_synchronization(value_binding, context) {
289
289
* value = $.spread_attributes(element, value, [...])
290
290
* });
291
291
* ```
292
- * Returns the id of the spread_attribute variable if spread is deemed reactive , `null` otherwise.
292
+ * Returns the id of the spread_attribute variable if spread isn't isolated , `null` otherwise.
293
293
* @param {Array<import('#compiler').Attribute | import('#compiler').SpreadAttribute> } attributes
294
294
* @param {import('../types.js').ComponentContext } context
295
295
* @param {import('#compiler').RegularElement } element
296
296
* @param {import('estree').Identifier } element_id
297
297
* @returns {string | null }
298
298
*/
299
299
function serialize_element_spread_attributes ( attributes , context , element , element_id ) {
300
- let is_reactive = false ;
300
+ let needs_isolation = false ;
301
301
302
302
/** @type {import('estree').Expression[] } */
303
303
const values = [ ] ;
@@ -312,19 +312,32 @@ function serialize_element_spread_attributes(attributes, context, element, eleme
312
312
values . push ( /** @type {import('estree').Expression } */ ( context . visit ( attribute ) ) ) ;
313
313
}
314
314
315
- is_reactive ||=
316
- attribute . metadata . dynamic ||
317
- // objects could contain reactive getters -> play it safe and always assume spread attributes are reactive
318
- attribute . type === 'SpreadAttribute' ;
315
+ needs_isolation ||=
316
+ attribute . type === 'SpreadAttribute' && attribute . metadata . contains_call_expression ;
319
317
}
320
318
321
319
const lowercase_attributes =
322
320
element . metadata . svg || is_custom_element_node ( element ) ? b . false : b . true ;
323
321
324
- if ( is_reactive ) {
322
+ const isolated = b . stmt (
323
+ b . call (
324
+ '$.spread_attributes_effect' ,
325
+ element_id ,
326
+ b . thunk ( b . array ( values ) ) ,
327
+ lowercase_attributes ,
328
+ b . literal ( context . state . analysis . stylesheet . id )
329
+ )
330
+ ) ;
331
+
332
+ // objects could contain reactive getters -> play it safe and always assume spread attributes are reactive
333
+ if ( needs_isolation ) {
334
+ context . state . update_effects . push ( isolated ) ;
335
+ return null ;
336
+ } else {
325
337
const id = context . state . scope . generate ( 'spread_attributes' ) ;
326
- context . state . init . push ( b . let ( id , undefined ) ) ;
338
+ context . state . init . push ( b . let ( id ) ) ;
327
339
context . state . update . push ( {
340
+ singular : isolated ,
328
341
grouped : b . stmt (
329
342
b . assignment (
330
343
'=' ,
@@ -341,20 +354,6 @@ function serialize_element_spread_attributes(attributes, context, element, eleme
341
354
)
342
355
} ) ;
343
356
return id ;
344
- } else {
345
- context . state . init . push (
346
- b . stmt (
347
- b . call (
348
- '$.spread_attributes' ,
349
- element_id ,
350
- b . literal ( null ) ,
351
- b . array ( values ) ,
352
- lowercase_attributes ,
353
- b . literal ( context . state . analysis . stylesheet . id )
354
- )
355
- )
356
- ) ;
357
- return null ;
358
357
}
359
358
}
360
359
@@ -366,7 +365,7 @@ function serialize_element_spread_attributes(attributes, context, element, eleme
366
365
* @param {import('estree').Identifier } element_id
367
366
* @returns {boolean }
368
367
*/
369
- function serialize_dynamic_element_spread_attributes ( attributes , context , element_id ) {
368
+ function serialize_dynamic_element_attributes ( attributes , context , element_id ) {
370
369
if ( attributes . length === 0 ) {
371
370
if ( context . state . analysis . stylesheet . id ) {
372
371
context . state . init . push (
@@ -376,6 +375,7 @@ function serialize_dynamic_element_spread_attributes(attributes, context, elemen
376
375
return false ;
377
376
}
378
377
378
+ let needs_isolation = false ;
379
379
let is_reactive = false ;
380
380
381
381
/** @type {import('estree').Expression[] } */
@@ -393,12 +393,27 @@ function serialize_dynamic_element_spread_attributes(attributes, context, elemen
393
393
attribute . metadata . dynamic ||
394
394
// objects could contain reactive getters -> play it safe and always assume spread attributes are reactive
395
395
attribute . type === 'SpreadAttribute' ;
396
+ needs_isolation ||=
397
+ attribute . type === 'SpreadAttribute' && attribute . metadata . contains_call_expression ;
396
398
}
397
399
398
- if ( is_reactive ) {
400
+ const isolated = b . stmt (
401
+ b . call (
402
+ '$.spread_dynamic_element_attributes_effect' ,
403
+ element_id ,
404
+ b . thunk ( b . array ( values ) ) ,
405
+ b . literal ( context . state . analysis . stylesheet . id )
406
+ )
407
+ ) ;
408
+
409
+ if ( needs_isolation ) {
410
+ context . state . update_effects . push ( isolated ) ;
411
+ return false ;
412
+ } else if ( is_reactive ) {
399
413
const id = context . state . scope . generate ( 'spread_attributes' ) ;
400
414
context . state . init . push ( b . let ( id ) ) ;
401
415
context . state . update . push ( {
416
+ singular : isolated ,
402
417
grouped : b . stmt (
403
418
b . assignment (
404
419
'=' ,
@@ -2105,7 +2120,7 @@ export const template_visitors = {
2105
2120
// Always use spread because we don't know whether the element is a custom element or not,
2106
2121
// therefore we need to do the "how to set an attribute" logic at runtime.
2107
2122
const is_attributes_reactive =
2108
- serialize_dynamic_element_spread_attributes ( attributes , inner_context , element_id ) !== null ;
2123
+ serialize_dynamic_element_attributes ( attributes , inner_context , element_id ) !== null ;
2109
2124
2110
2125
// class/style directives must be applied last since they could override class/style attributes
2111
2126
serialize_class_directives ( class_directives , element_id , inner_context , is_attributes_reactive ) ;
0 commit comments