11import { key } from './render.js' ;
2- import { source , set , get } from './runtime.js' ;
2+ import { source , set , get , push , pop , user_effect } from './runtime.js' ;
33import { current_hydration_fragment } from './hydration.js' ;
44import { child_frag } from './operations.js' ;
5- import { proxy } from './proxy/proxy.js' ;
5+ import { STATE_SYMBOL , proxy } from './proxy/proxy.js' ;
66
77/**
88 * @typedef {Record<string | symbol, any> | undefined } ComponentReturn
@@ -17,41 +17,96 @@ import { proxy } from './proxy/proxy.js';
1717 * }} HotData<Component>
1818 */
1919
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 ] ;
3653 }
37- node = node . previousSibling ;
54+
55+ return null ;
3856 }
3957
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 ) ;
4665 }
47- node = node . nextSibling ;
4866 }
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 ( ) ;
4973
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+ }
52107 }
53108
54- return null ;
109+ return { accessors_proxy , sync_accessors_proxy } ;
55110}
56111
57112/**
@@ -71,10 +126,10 @@ function create_proxy_component(new_component) {
71126 }
72127
73128 // @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 ( ) ;
78133
79134 // During hydration the root component will receive a null $$anchor. The
80135 // 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) {
86141 // still work after that... Maybe we can show a more specific error message than
87142 // the generic hydration failure one (that could be misleading in this case).
88143 //
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 ;
97146 }
98147
99148 key (
@@ -103,25 +152,14 @@ function create_proxy_component(new_component) {
103152 const component = get ( component_signal ) ;
104153
105154 // @ts -ignore
106- const new_accessors = component ( $$anchor , ... args ) ;
155+ const new_accessors = component ( $$anchor , $$props ) ;
107156
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 ) ;
122158 }
123159 ) ;
124160
161+ pop ( accessors_proxy ) ;
162+
125163 return accessors_proxy ;
126164 }
127165
@@ -132,6 +170,7 @@ function create_proxy_component(new_component) {
132170 }
133171 } ) ;
134172 } catch ( err ) {
173+ // eslint-disable-next-line no-console
135174 console . warn ( "[Svelte HMR] Failed to proxy component function's name" , err ) ;
136175 }
137176
0 commit comments