1
1
import { key } from './render.js' ;
2
- import { source , set , get } from './runtime.js' ;
2
+ import { source , set , get , push , pop , user_effect } from './runtime.js' ;
3
3
import { current_hydration_fragment } from './hydration.js' ;
4
4
import { child_frag } from './operations.js' ;
5
- import { proxy } from './proxy/proxy.js' ;
5
+ import { STATE_SYMBOL , proxy } from './proxy/proxy.js' ;
6
6
7
7
/**
8
8
* @typedef {Record<string | symbol, any> | undefined } ComponentReturn
@@ -17,41 +17,96 @@ import { proxy } from './proxy/proxy.js';
17
17
* }} HotData<Component>
18
18
*/
19
19
20
- function find_surrounding_ssr_commments ( ) {
21
- if ( ! current_hydration_fragment ?. [ 0 ] ) return null ;
22
-
23
- /** @type {Comment | undefined } */
24
- let before ;
25
- /** @type {Comment | undefined } */
26
- let after ;
27
- /** @type {Node | null | undefined } */
28
- let node ;
29
-
30
- node = current_hydration_fragment [ 0 ] . previousSibling ;
31
- while ( node ) {
32
- const comment = /** @type {Comment } */ ( node ) ;
33
- if ( node . nodeType === 8 && comment . data . startsWith ( 'ssr:' ) ) {
34
- before = comment ;
35
- break ;
20
+ function get_hydration_root ( ) {
21
+ function find_surrounding_ssr_commments ( ) {
22
+ if ( ! current_hydration_fragment ?. [ 0 ] ) return null ;
23
+
24
+ /** @type {Comment | undefined } */
25
+ let before ;
26
+ /** @type {Comment | undefined } */
27
+ let after ;
28
+ /** @type {Node | null | undefined } */
29
+ let node ;
30
+
31
+ node = current_hydration_fragment [ 0 ] . previousSibling ;
32
+ while ( node ) {
33
+ const comment = /** @type {Comment } */ ( node ) ;
34
+ if ( node . nodeType === 8 && comment . data . startsWith ( 'ssr:' ) ) {
35
+ before = comment ;
36
+ break ;
37
+ }
38
+ node = node . previousSibling ;
39
+ }
40
+
41
+ node = current_hydration_fragment . at ( - 1 ) ?. nextSibling ;
42
+ while ( node ) {
43
+ const comment = /** @type {Comment } */ ( node ) ;
44
+ if ( node . nodeType === 8 && comment . data . startsWith ( 'ssr:' ) ) {
45
+ after = comment ;
46
+ break ;
47
+ }
48
+ node = node . nextSibling ;
49
+ }
50
+
51
+ if ( before && after && before . data === after . data ) {
52
+ return [ before , after ] ;
36
53
}
37
- node = node . previousSibling ;
54
+
55
+ return null ;
38
56
}
39
57
40
- node = current_hydration_fragment . at ( - 1 ) ?. nextSibling ;
41
- while ( node ) {
42
- const comment = /** @type {Comment } */ ( node ) ;
43
- if ( node . nodeType === 8 && comment . data . startsWith ( 'ssr:' ) ) {
44
- after = comment ;
45
- break ;
58
+ if ( current_hydration_fragment ) {
59
+ const ssr0 = find_surrounding_ssr_commments ( ) ;
60
+ if ( ssr0 ) {
61
+ const [ before , after ] = ssr0 ;
62
+ current_hydration_fragment . unshift ( before ) ;
63
+ current_hydration_fragment . push ( after ) ;
64
+ return child_frag ( current_hydration_fragment ) ;
46
65
}
47
- node = node . nextSibling ;
48
66
}
67
+ }
68
+
69
+ function create_accessors_proxy ( ) {
70
+ const accessors_proxy = proxy ( /** @type {import('./proxy/proxy.js').StateObject } */ ( { } ) ) ;
71
+ /** @type {Set<string> } */
72
+ const accessors_keys = new Set ( ) ;
49
73
50
- if ( before && after && before . data === after . data ) {
51
- return [ before , after ] ;
74
+ /**
75
+ * @param {ComponentReturn } new_accessors
76
+ */
77
+ function sync_accessors_proxy ( new_accessors ) {
78
+ const removed_keys = new Set ( accessors_keys ) ;
79
+
80
+ if ( new_accessors ) {
81
+ for ( const key in new_accessors ) {
82
+ accessors_keys . add ( key ) ;
83
+ removed_keys . delete ( key ) ;
84
+
85
+ // current -> proxy
86
+ user_effect ( ( ) => {
87
+ accessors_proxy [ key ] = new_accessors [ key ] ;
88
+ } )
89
+
90
+ // proxy -> current
91
+ const descriptor = Object . getOwnPropertyDescriptor ( new_accessors , key ) ;
92
+ if ( descriptor ?. set || descriptor ?. writable ) {
93
+ user_effect ( ( ) => {
94
+ const s = accessors_proxy [ STATE_SYMBOL ] . s . get ( key ) ;
95
+ if ( s ) {
96
+ new_accessors [ key ] = get ( s ) ;
97
+ }
98
+ } ) ;
99
+ }
100
+ }
101
+ }
102
+
103
+ for ( const key of removed_keys ) {
104
+ accessors_keys . delete ( key ) ;
105
+ accessors_proxy [ key ] = undefined ;
106
+ }
52
107
}
53
108
54
- return null ;
109
+ return { accessors_proxy , sync_accessors_proxy } ;
55
110
}
56
111
57
112
/**
@@ -71,10 +126,10 @@ function create_proxy_component(new_component) {
71
126
}
72
127
73
128
// @ts -ignore
74
- function proxy_component ( $$anchor , ... args ) {
75
- const accessors_proxy = proxy ( /** @type { import('./proxy/proxy.js').StateObject } */ ( { } ) ) ;
76
- /** @type { Set<string> } */
77
- const accessors_keys = new Set ( ) ;
129
+ function proxy_component ( $$anchor , $$props ) {
130
+ push ( $$props ) ;
131
+
132
+ const { accessors_proxy , sync_accessors_proxy } = create_accessors_proxy ( ) ;
78
133
79
134
// During hydration the root component will receive a null $$anchor. The
80
135
// following is a hack to get our `key` a node to render to, all while
@@ -86,14 +141,8 @@ function create_proxy_component(new_component) {
86
141
// still work after that... Maybe we can show a more specific error message than
87
142
// the generic hydration failure one (that could be misleading in this case).
88
143
//
89
- if ( ! $$anchor && current_hydration_fragment ?. [ 0 ] ) {
90
- const ssr0 = find_surrounding_ssr_commments ( ) ;
91
- if ( ssr0 ) {
92
- const [ before , after ] = ssr0 ;
93
- current_hydration_fragment . unshift ( before ) ;
94
- current_hydration_fragment . push ( after ) ;
95
- $$anchor = child_frag ( current_hydration_fragment ) ;
96
- }
144
+ if ( ! $$anchor ) {
145
+ $$anchor = get_hydration_root ( ) || $$anchor ;
97
146
}
98
147
99
148
key (
@@ -103,25 +152,14 @@ function create_proxy_component(new_component) {
103
152
const component = get ( component_signal ) ;
104
153
105
154
// @ts -ignore
106
- const new_accessors = component ( $$anchor , ... args ) ;
155
+ const new_accessors = component ( $$anchor , $$props ) ;
107
156
108
- const removed_keys = new Set ( accessors_keys ) ;
109
-
110
- if ( new_accessors ) {
111
- for ( const [ key , value ] of Object . entries ( new_accessors ) ) {
112
- accessors_proxy [ key ] = value ;
113
- accessors_keys . add ( key ) ;
114
- removed_keys . delete ( key ) ;
115
- }
116
- }
117
-
118
- for ( const key of removed_keys ) {
119
- accessors_keys . delete ( key ) ;
120
- accessors_proxy [ key ] = undefined ;
121
- }
157
+ sync_accessors_proxy ( new_accessors ) ;
122
158
}
123
159
) ;
124
160
161
+ pop ( accessors_proxy ) ;
162
+
125
163
return accessors_proxy ;
126
164
}
127
165
@@ -132,6 +170,7 @@ function create_proxy_component(new_component) {
132
170
}
133
171
} ) ;
134
172
} catch ( err ) {
173
+ // eslint-disable-next-line no-console
135
174
console . warn ( "[Svelte HMR] Failed to proxy component function's name" , err ) ;
136
175
}
137
176
0 commit comments