@@ -13,9 +13,11 @@ import { on } from './event'
13
13
import {
14
14
MismatchTypes ,
15
15
currentInstance ,
16
+ getAttributeMismatch ,
16
17
isMapEqual ,
17
18
isMismatchAllowed ,
18
19
isSetEqual ,
20
+ isValidHtmlOrSvgAttribute ,
19
21
mergeProps ,
20
22
patchStyle ,
21
23
shouldSetAsProp ,
@@ -67,6 +69,15 @@ export function setAttr(el: any, key: string, value: any): void {
67
69
; ( el as any ) . _falseValue = value
68
70
}
69
71
72
+ if (
73
+ ( __DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__ ) &&
74
+ isHydrating &&
75
+ ! attributeHasMismatch ( el , key , value )
76
+ ) {
77
+ el [ `$${ key } ` ] = value
78
+ return
79
+ }
80
+
70
81
if ( value !== el [ `$${ key } ` ] ) {
71
82
el [ `$${ key } ` ] = value
72
83
if ( value != null ) {
@@ -82,6 +93,14 @@ export function setDOMProp(el: any, key: string, value: any): void {
82
93
return
83
94
}
84
95
96
+ if (
97
+ ( __DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__ ) &&
98
+ isHydrating &&
99
+ ! attributeHasMismatch ( el , key , value )
100
+ ) {
101
+ return
102
+ }
103
+
85
104
const prev = el [ key ]
86
105
if ( value === prev ) {
87
106
return
@@ -123,32 +142,37 @@ export function setClass(el: TargetElement, value: any): void {
123
142
if ( el . $root ) {
124
143
setClassIncremental ( el , value )
125
144
} else {
145
+ value = normalizeClass ( value )
126
146
if (
127
147
( __DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__ ) &&
128
- isHydrating
148
+ isHydrating &&
149
+ ! classHasMismatch ( el , value , false )
129
150
) {
130
- const expected = normalizeClass ( value )
131
- handleClassHydration ( el , value , expected , false , '$cls' )
151
+ el . $cls = value
132
152
return
133
153
}
134
154
135
- if ( ( value = normalizeClass ( value ) ) !== el . $cls ) {
155
+ if ( value !== el . $cls ) {
136
156
el . className = el . $cls = value
137
157
}
138
158
}
139
159
}
140
160
141
161
function setClassIncremental ( el : any , value : any ) : void {
142
162
const cacheKey = `$clsi${ isApplyingFallthroughProps ? '$' : '' } `
163
+ const normalizedValue = normalizeClass ( value )
143
164
144
- if ( ( __DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__ ) && isHydrating ) {
145
- const expected = normalizeClass ( value )
146
- handleClassHydration ( el , value , expected , true , cacheKey )
165
+ if (
166
+ ( __DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__ ) &&
167
+ isHydrating &&
168
+ ! classHasMismatch ( el , normalizedValue , true )
169
+ ) {
170
+ el [ cacheKey ] = normalizedValue
147
171
return
148
172
}
149
173
150
174
const prev = el [ cacheKey ]
151
- if ( ( value = el [ cacheKey ] = normalizeClass ( value ) ) !== prev ) {
175
+ if ( ( value = el [ cacheKey ] = normalizedValue ) !== prev ) {
152
176
const nextList = value . split ( / \s + / )
153
177
if ( value ) {
154
178
el . classList . add ( ...nextList )
@@ -165,16 +189,17 @@ export function setStyle(el: TargetElement, value: any): void {
165
189
if ( el . $root ) {
166
190
setStyleIncremental ( el , value )
167
191
} else {
192
+ const normalizedValue = normalizeStyle ( value )
168
193
if (
169
194
( __DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__ ) &&
170
- isHydrating
195
+ isHydrating &&
196
+ ! styleHasMismatch ( el , value , normalizedValue , false )
171
197
) {
172
- const normalizedValue = normalizeStyle ( value )
173
- handleStyleHydration ( el , value , normalizedValue , false , '$sty' )
198
+ el . $sty = normalizedValue
174
199
return
175
200
}
176
201
177
- patchStyle ( el , el . $sty , ( el . $sty = normalizeStyle ( value ) ) )
202
+ patchStyle ( el , el . $sty , ( el . $sty = normalizedValue ) )
178
203
}
179
204
}
180
205
@@ -184,8 +209,12 @@ function setStyleIncremental(el: any, value: any): NormalizedStyle | undefined {
184
209
? parseStringStyle ( value )
185
210
: ( normalizeStyle ( value ) as NormalizedStyle | undefined )
186
211
187
- if ( ( __DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__ ) && isHydrating ) {
188
- handleStyleHydration ( el , value , normalizedValue , true , cacheKey )
212
+ if (
213
+ ( __DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__ ) &&
214
+ isHydrating &&
215
+ ! styleHasMismatch ( el , value , normalizedValue , true )
216
+ ) {
217
+ el [ cacheKey ] = normalizedValue
189
218
return
190
219
}
191
220
@@ -197,6 +226,14 @@ export function setValue(el: TargetElement, value: any): void {
197
226
return
198
227
}
199
228
229
+ if (
230
+ ( __DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__ ) &&
231
+ isHydrating &&
232
+ ! attributeHasMismatch ( el , 'value' , value )
233
+ ) {
234
+ return
235
+ }
236
+
200
237
// store value as _value as well since
201
238
// non-string values will be stringified.
202
239
el . _value = value
@@ -219,20 +256,19 @@ export function setValue(el: TargetElement, value: any): void {
219
256
*/
220
257
export function setText ( el : Text & { $txt ?: string } , value : string ) : void {
221
258
if ( isHydrating ) {
222
- if ( el . nodeValue !== value ) {
223
- ; ( __DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__ ) &&
224
- warn (
225
- `Hydration text mismatch in` ,
226
- el . parentNode ,
227
- `\n - rendered on server: ${ JSON . stringify ( ( el as Text ) . data ) } ` +
228
- `\n - expected on client: ${ JSON . stringify ( value ) } ` ,
229
- )
230
- logMismatchError ( )
231
- el . nodeValue = value
259
+ if ( el . nodeValue == value ) {
260
+ el . $txt = value
261
+ return
232
262
}
233
263
234
- el . $txt = value
235
- return
264
+ ; ( __DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__ ) &&
265
+ warn (
266
+ `Hydration text mismatch in` ,
267
+ el . parentNode ,
268
+ `\n - rendered on server: ${ JSON . stringify ( ( el as Text ) . data ) } ` +
269
+ `\n - expected on client: ${ JSON . stringify ( value ) } ` ,
270
+ )
271
+ logMismatchError ( )
236
272
}
237
273
238
274
if ( el . $txt !== value ) {
@@ -258,22 +294,21 @@ export function setElementText(
258
294
clientText = clientText . slice ( 1 )
259
295
}
260
296
261
- if ( el . textContent !== clientText ) {
262
- if ( ! isMismatchAllowed ( el as Element , MismatchTypes . TEXT ) ) {
263
- ; ( __DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__ ) &&
264
- warn (
265
- `Hydration text content mismatch on` ,
266
- el ,
267
- `\n - rendered on server: ${ el . textContent } ` +
268
- `\n - expected on client: ${ clientText } ` ,
269
- )
270
- logMismatchError ( )
271
- }
272
- el . textContent = clientText
297
+ if ( el . textContent === clientText ) {
298
+ el . $txt = clientText
299
+ return
273
300
}
274
301
275
- el . $txt = clientText
276
- return
302
+ if ( ! isMismatchAllowed ( el as Element , MismatchTypes . TEXT ) ) {
303
+ ; ( __DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__ ) &&
304
+ warn (
305
+ `Hydration text content mismatch on` ,
306
+ el ,
307
+ `\n - rendered on server: ${ el . textContent } ` +
308
+ `\n - expected on client: ${ clientText } ` ,
309
+ )
310
+ logMismatchError ( )
311
+ }
277
312
}
278
313
279
314
if ( el . $txt !== value ) {
@@ -285,22 +320,21 @@ export function setHtml(el: TargetElement, value: any): void {
285
320
value = value == null ? '' : value
286
321
287
322
if ( isHydrating ) {
288
- if ( el . innerHTML !== value ) {
289
- if ( ! isMismatchAllowed ( el , MismatchTypes . CHILDREN ) ) {
290
- if ( __DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__ ) {
291
- warn (
292
- `Hydration children mismatch on` ,
293
- el ,
294
- `\nServer rendered element contains different child nodes from client nodes.` ,
295
- )
296
- }
297
- logMismatchError ( )
298
- }
299
- el . innerHTML = value
323
+ if ( el . innerHTML === value ) {
324
+ el . $html = value
325
+ return
300
326
}
301
327
302
- el . $html = value
303
- return
328
+ if ( ! isMismatchAllowed ( el , MismatchTypes . CHILDREN ) ) {
329
+ if ( __DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__ ) {
330
+ warn (
331
+ `Hydration children mismatch on` ,
332
+ el ,
333
+ `\nServer rendered element contains different child nodes from client nodes.` ,
334
+ )
335
+ }
336
+ logMismatchError ( )
337
+ }
304
338
}
305
339
306
340
if ( el . $html !== value ) {
@@ -384,13 +418,11 @@ export function optimizePropertyLookup(): void {
384
418
''
385
419
}
386
420
387
- function handleClassHydration (
421
+ function classHasMismatch (
388
422
el : TargetElement | any ,
389
- value : any ,
390
423
expected : string ,
391
424
isIncremental : boolean ,
392
- cacheKey : string ,
393
- ) {
425
+ ) : boolean {
394
426
const actual = el . getAttribute ( 'class' )
395
427
const actualClassSet = toClassSet ( actual || '' )
396
428
const expectedClassSet = toClassSet ( expected )
@@ -403,27 +435,18 @@ function handleClassHydration(
403
435
if ( hasMismatch ) {
404
436
warnPropMismatch ( el , 'class' , MismatchTypes . CLASS , actual , expected )
405
437
logMismatchError ( )
406
-
407
- if ( isIncremental ) {
408
- const nextList = value . split ( / \s + / )
409
- if ( value ) {
410
- el . classList . add ( ...nextList )
411
- }
412
- } else {
413
- el . className = expected
414
- }
438
+ return true
415
439
}
416
440
417
- el [ cacheKey ] = expected
441
+ return false
418
442
}
419
443
420
- function handleStyleHydration (
444
+ function styleHasMismatch (
421
445
el : TargetElement | any ,
422
446
value : any ,
423
447
normalizedValue : string | NormalizedStyle | undefined ,
424
448
isIncremental : boolean ,
425
- cacheKey : string ,
426
- ) {
449
+ ) : boolean {
427
450
const actual = el . getAttribute ( 'style' )
428
451
const actualStyleMap = toStyleMap ( actual || '' )
429
452
const expected = isString ( value ) ? value : stringifyStyle ( normalizedValue )
@@ -446,8 +469,20 @@ function handleStyleHydration(
446
469
if ( hasMismatch ) {
447
470
warnPropMismatch ( el , 'style' , MismatchTypes . STYLE , actual , expected )
448
471
logMismatchError ( )
449
- patchStyle ( el , el [ cacheKey ] , ( el [ cacheKey ] = normalizedValue ) )
472
+ return true
450
473
}
451
474
452
- el [ cacheKey ] = normalizedValue
475
+ return false
476
+ }
477
+
478
+ function attributeHasMismatch ( el : any , key : string , value : any ) : boolean {
479
+ if ( isValidHtmlOrSvgAttribute ( el , key ) ) {
480
+ const { actual, expected } = getAttributeMismatch ( el , key , value )
481
+ if ( actual !== expected ) {
482
+ warnPropMismatch ( el , key , MismatchTypes . ATTRIBUTE , actual , expected )
483
+ logMismatchError ( )
484
+ return true
485
+ }
486
+ }
487
+ return false
453
488
}
0 commit comments