@@ -16,28 +16,30 @@ import { build_template_chunk, get_expression_id } from './utils.js';
1616 * @param  {ComponentContext } context 
1717 * @param  {AST.RegularElement | AST.SvelteElement } element 
1818 * @param  {Identifier } element_id 
19-  * @param  {Identifier } attributes_id 
2019 */ 
21- export  function  build_set_attributes ( 
20+ export  function  build_attribute_effect ( 
2221	attributes , 
2322	class_directives , 
2423	style_directives , 
2524	context , 
2625	element , 
27- 	element_id , 
28- 	attributes_id 
26+ 	element_id 
2927)  { 
30- 	let  is_dynamic  =  false ; 
31- 
3228	/** @type  {ObjectExpression['properties'] } */ 
3329	const  values  =  [ ] ; 
3430
31+ 	/** @type  {Expression[] } */ 
32+ 	const  expressions  =  [ ] ; 
33+ 
34+ 	/** @param  {Expression } value */ 
35+ 	function  memoize ( value )  { 
36+ 		return  b . id ( `$${ expressions . push ( value )  -  1 }  ` ) ; 
37+ 	} 
38+ 
3539	for  ( const  attribute  of  attributes )  { 
3640		if  ( attribute . type  ===  'Attribute' )  { 
37- 			const  {  value,  has_state }  =  build_attribute_value ( 
38- 				attribute . value , 
39- 				context , 
40- 				( value ,  metadata )  =>  ( metadata . has_call  ? get_expression_id ( context . state ,  value )  : value ) 
41+ 			const  {  value }  =  build_attribute_value ( attribute . value ,  context ,  ( value ,  metadata )  => 
42+ 				metadata . has_call  ? memoize ( value )  : value 
4143			) ; 
4244
4345			if  ( 
@@ -51,16 +53,11 @@ export function build_set_attributes(
5153			}  else  { 
5254				values . push ( b . init ( attribute . name ,  value ) ) ; 
5355			} 
54- 
55- 			is_dynamic  ||=  has_state ; 
5656		}  else  { 
57- 			// objects could contain reactive getters -> play it safe and always assume spread attributes are reactive 
58- 			is_dynamic  =  true ; 
59- 
6057			let  value  =  /** @type  {Expression } */  ( context . visit ( attribute ) ) ; 
6158
6259			if  ( attribute . metadata . expression . has_call )  { 
63- 				value  =  get_expression_id ( context . state ,   value ) ; 
60+ 				value  =  memoize ( value ) ; 
6461			} 
6562
6663			values . push ( b . spread ( value ) ) ; 
@@ -72,44 +69,38 @@ export function build_set_attributes(
7269			b . prop ( 
7370				'init' , 
7471				b . array ( [ b . id ( '$.CLASS' ) ] ) , 
75- 				build_class_directives_object ( class_directives ,  context ) 
72+ 				build_class_directives_object ( class_directives ,  expressions ,   context ) 
7673			) 
7774		) ; 
78- 
79- 		is_dynamic  ||= 
80- 			class_directives . find ( ( directive )  =>  directive . metadata . expression . has_state )  !==  null ; 
8175	} 
8276
8377	if  ( style_directives . length )  { 
8478		values . push ( 
8579			b . prop ( 
8680				'init' , 
8781				b . array ( [ b . id ( '$.STYLE' ) ] ) , 
88- 				build_style_directives_object ( style_directives ,  context ) 
82+ 				build_style_directives_object ( style_directives ,  expressions ,   context ) 
8983			) 
9084		) ; 
91- 
92- 		is_dynamic  ||=  style_directives . some ( ( directive )  =>  directive . metadata . expression . has_state ) ; 
9385	} 
9486
95- 	const  call  =  b . call ( 
96- 		'$.set_attributes' , 
97- 		element_id , 
98- 		is_dynamic  ? attributes_id  : b . null , 
99- 		b . object ( values ) , 
100- 		element . metadata . scoped  && 
101- 			context . state . analysis . css . hash  !==  ''  && 
102- 			b . literal ( context . state . analysis . css . hash ) , 
103- 		is_ignored ( element ,  'hydration_attribute_changed' )  &&  b . true 
87+ 	context . state . init . push ( 
88+ 		b . stmt ( 
89+ 			b . call ( 
90+ 				'$.attribute_effect' , 
91+ 				element_id , 
92+ 				b . arrow ( 
93+ 					expressions . map ( ( _ ,  i )  =>  b . id ( `$${ i }  ` ) ) , 
94+ 					b . object ( values ) 
95+ 				) , 
96+ 				expressions . length  >  0  &&  b . array ( expressions . map ( ( expression )  =>  b . thunk ( expression ) ) ) , 
97+ 				element . metadata . scoped  && 
98+ 					context . state . analysis . css . hash  !==  ''  && 
99+ 					b . literal ( context . state . analysis . css . hash ) , 
100+ 				is_ignored ( element ,  'hydration_attribute_changed' )  &&  b . true 
101+ 			) 
102+ 		) 
104103	) ; 
105- 
106- 	if  ( is_dynamic )  { 
107- 		context . state . init . push ( b . let ( attributes_id ) ) ; 
108- 		const  update  =  b . stmt ( b . assignment ( '=' ,  attributes_id ,  call ) ) ; 
109- 		context . state . update . push ( update ) ; 
110- 	}  else  { 
111- 		context . state . init . push ( b . stmt ( call ) ) ; 
112- 	} 
113104} 
114105
115106/** 
@@ -167,7 +158,7 @@ export function build_set_class(element, node_id, attribute, class_directives, c
167158			value  =  b . call ( '$.clsx' ,  value ) ; 
168159		} 
169160
170- 		return  metadata . has_call  ? get_expression_id ( context . state ,  value )  : value ; 
161+ 		return  metadata . has_call  ? get_expression_id ( context . state . expressions ,  value )  : value ; 
171162	} ) ; 
172163
173164	/** @type  {Identifier | undefined } */ 
@@ -180,7 +171,7 @@ export function build_set_class(element, node_id, attribute, class_directives, c
180171	let  next ; 
181172
182173	if  ( class_directives . length )  { 
183- 		next  =  build_class_directives_object ( class_directives ,  context ) ; 
174+ 		next  =  build_class_directives_object ( class_directives ,  context . state . expressions ,   context ) ; 
184175		has_state  ||=  class_directives . some ( ( d )  =>  d . metadata . expression . has_state ) ; 
185176
186177		if  ( has_state )  { 
@@ -235,7 +226,7 @@ export function build_set_class(element, node_id, attribute, class_directives, c
235226 */ 
236227export  function  build_set_style ( node_id ,  attribute ,  style_directives ,  context )  { 
237228	let  {  value,  has_state }  =  build_attribute_value ( attribute . value ,  context ,  ( value ,  metadata )  => 
238- 		metadata . has_call  ? get_expression_id ( context . state ,  value )  : value 
229+ 		metadata . has_call  ? get_expression_id ( context . state . expressions ,  value )  : value 
239230	) ; 
240231
241232	/** @type  {Identifier | undefined } */ 
@@ -248,7 +239,7 @@ export function build_set_style(node_id, attribute, style_directives, context) {
248239	let  next ; 
249240
250241	if  ( style_directives . length )  { 
251- 		next  =  build_style_directives_object ( style_directives ,  context ) ; 
242+ 		next  =  build_style_directives_object ( style_directives ,  context . state . expressions ,   context ) ; 
252243		has_state  ||=  style_directives . some ( ( d )  =>  d . metadata . expression . has_state ) ; 
253244
254245		if  ( has_state )  { 
0 commit comments