@@ -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