1
- import { key } from './render.js' ;
1
+ import { key , comment } from './render.js' ;
2
2
import { source , set , get } from './runtime.js' ;
3
+ import { current_hydration_fragment } from './hydration.js' ;
4
+ import { child_frag } from './operations.js' ;
5
+
6
+ function find_surrounding_ssr_commments ( ) {
7
+ if ( ! current_hydration_fragment ?. [ 0 ] ) return null ;
8
+
9
+ /** @type {Comment | undefined } */
10
+ let before ;
11
+ /** @type {Comment | undefined } */
12
+ let after ;
13
+ /** @type {Node | null | undefined } */
14
+ let node ;
15
+
16
+ node = current_hydration_fragment [ 0 ] . previousSibling ;
17
+ while ( node ) {
18
+ const comment = /** @type {Comment } */ ( node ) ;
19
+ if ( node . nodeType === 8 && comment . data . startsWith ( 'ssr:' ) ) {
20
+ before = comment ;
21
+ break ;
22
+ }
23
+ node = node . previousSibling ;
24
+ }
25
+
26
+ node = current_hydration_fragment . at ( - 1 ) ?. nextSibling ;
27
+ while ( node ) {
28
+ const comment = /** @type {Comment } */ ( node ) ;
29
+ if ( node . nodeType === 8 && comment . data . startsWith ( 'ssr:' ) ) {
30
+ after = comment ;
31
+ break ;
32
+ }
33
+ node = node . nextSibling ;
34
+ }
35
+
36
+ if ( before && after && before . data === after . data ) {
37
+ return [ before , after ] ;
38
+ }
39
+
40
+ return null ;
41
+ }
3
42
4
43
/**
5
44
* @template {any[]} ComponentArgs
@@ -10,38 +49,53 @@ import { source, set, get } from './runtime.js';
10
49
* component_signal: ReturnType<typeof source<Component>>,
11
50
* proxy?: (...args: ComponentArgs) => ComponentReturn
12
51
* }} hot_data
13
- * @param {Component } component
52
+ * @param {Component } new_component
14
53
*/
15
- export function hmr ( hot_data , component ) {
54
+ export function hmr ( hot_data , new_component ) {
16
55
if ( hot_data . proxy ) {
17
- set ( hot_data . component_signal , component ) ;
56
+ set ( hot_data . component_signal , new_component ) ;
18
57
} else {
19
- const component_signal = ( hot_data . component_signal = source ( component ) ) ;
58
+ const component_signal = source ( new_component ) ;
59
+
60
+ hot_data . component_signal = component_signal ;
20
61
21
62
// @ts -ignore
22
- hot_data . proxy = function ( target , ...args ) {
23
- const accessors = source ( /** @type {ComponentReturn } */ ( { } ) ) ;
63
+ hot_data . proxy = function ( $$anchor , ...args ) {
64
+ let accessors = /** @type {ComponentReturn } */ ( { } ) ;
65
+
66
+ // During hydration the root component will receive a null $$anchor. The
67
+ // following is a hack to get our `key` a node to render to, all while
68
+ // avoiding it to "consume" the SSR marker.
69
+ // TODO better get the eyes of someone with understanding of hydration on this
70
+ if ( ! $$anchor && current_hydration_fragment ?. [ 0 ] ) {
71
+ const ssr0 = find_surrounding_ssr_commments ( ) ;
72
+ if ( ssr0 ) {
73
+ const [ before , after ] = ssr0 ;
74
+ current_hydration_fragment . unshift ( before ) ;
75
+ current_hydration_fragment . push ( after ) ;
76
+ $$anchor = child_frag ( current_hydration_fragment ) ;
77
+ }
78
+ }
24
79
25
80
key (
26
- target ,
81
+ $$anchor ,
27
82
( ) => get ( component_signal ) ,
28
83
( $$anchor ) => {
29
- const current_component = get ( component_signal ) ;
84
+ const component = get ( component_signal ) ;
30
85
// @ts -ignore
31
- const new_accessors = current_component ( $$anchor , ...args ) ;
32
- set ( accessors , new_accessors ) ;
86
+ accessors = component ( $$anchor , ...args ) ;
33
87
}
34
88
) ;
35
89
36
90
return new Proxy (
37
91
{ } ,
38
92
{
39
93
get ( _ , p ) {
40
- return get ( accessors ) ?. [ p ] ;
94
+ return accessors ?. [ p ] ;
41
95
} ,
42
96
set ( _ , p , value ) {
43
97
// @ts -ignore (we actually want to crash on undefined, like non HMR code would do)
44
- get ( accessors ) [ p ] = value ;
98
+ accessors [ p ] = value ;
45
99
return true ;
46
100
}
47
101
}
0 commit comments