@@ -13,9 +13,11 @@ import { on } from './event'
1313import {
1414 MismatchTypes ,
1515 currentInstance ,
16+ getAttributeMismatch ,
1617 isMapEqual ,
1718 isMismatchAllowed ,
1819 isSetEqual ,
20+ isValidHtmlOrSvgAttribute ,
1921 mergeProps ,
2022 patchStyle ,
2123 shouldSetAsProp ,
@@ -67,6 +69,15 @@ export function setAttr(el: any, key: string, value: any): void {
6769 ; ( el as any ) . _falseValue = value
6870 }
6971
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+
7081 if ( value !== el [ `$${ key } ` ] ) {
7182 el [ `$${ key } ` ] = value
7283 if ( value != null ) {
@@ -82,6 +93,14 @@ export function setDOMProp(el: any, key: string, value: any): void {
8293 return
8394 }
8495
96+ if (
97+ ( __DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__ ) &&
98+ isHydrating &&
99+ ! attributeHasMismatch ( el , key , value )
100+ ) {
101+ return
102+ }
103+
85104 const prev = el [ key ]
86105 if ( value === prev ) {
87106 return
@@ -123,32 +142,37 @@ export function setClass(el: TargetElement, value: any): void {
123142 if ( el . $root ) {
124143 setClassIncremental ( el , value )
125144 } else {
145+ value = normalizeClass ( value )
126146 if (
127147 ( __DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__ ) &&
128- isHydrating
148+ isHydrating &&
149+ ! classHasMismatch ( el , value , false )
129150 ) {
130- const expected = normalizeClass ( value )
131- handleClassHydration ( el , value , expected , false , '$cls' )
151+ el . $cls = value
132152 return
133153 }
134154
135- if ( ( value = normalizeClass ( value ) ) !== el . $cls ) {
155+ if ( value !== el . $cls ) {
136156 el . className = el . $cls = value
137157 }
138158 }
139159}
140160
141161function setClassIncremental ( el : any , value : any ) : void {
142162 const cacheKey = `$clsi${ isApplyingFallthroughProps ? '$' : '' } `
163+ const normalizedValue = normalizeClass ( value )
143164
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
147171 return
148172 }
149173
150174 const prev = el [ cacheKey ]
151- if ( ( value = el [ cacheKey ] = normalizeClass ( value ) ) !== prev ) {
175+ if ( ( value = el [ cacheKey ] = normalizedValue ) !== prev ) {
152176 const nextList = value . split ( / \s + / )
153177 if ( value ) {
154178 el . classList . add ( ...nextList )
@@ -165,16 +189,17 @@ export function setStyle(el: TargetElement, value: any): void {
165189 if ( el . $root ) {
166190 setStyleIncremental ( el , value )
167191 } else {
192+ const normalizedValue = normalizeStyle ( value )
168193 if (
169194 ( __DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__ ) &&
170- isHydrating
195+ isHydrating &&
196+ ! styleHasMismatch ( el , value , normalizedValue , false )
171197 ) {
172- const normalizedValue = normalizeStyle ( value )
173- handleStyleHydration ( el , value , normalizedValue , false , '$sty' )
198+ el . $sty = normalizedValue
174199 return
175200 }
176201
177- patchStyle ( el , el . $sty , ( el . $sty = normalizeStyle ( value ) ) )
202+ patchStyle ( el , el . $sty , ( el . $sty = normalizedValue ) )
178203 }
179204}
180205
@@ -184,8 +209,12 @@ function setStyleIncremental(el: any, value: any): NormalizedStyle | undefined {
184209 ? parseStringStyle ( value )
185210 : ( normalizeStyle ( value ) as NormalizedStyle | undefined )
186211
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
189218 return
190219 }
191220
@@ -200,6 +229,15 @@ export function setValue(el: TargetElement, value: any): void {
200229 // store value as _value as well since
201230 // non-string values will be stringified.
202231 el . _value = value
232+
233+ if (
234+ ( __DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__ ) &&
235+ isHydrating &&
236+ ! attributeHasMismatch ( el , 'value' , value )
237+ ) {
238+ return
239+ }
240+
203241 // #4956: <option> value will fallback to its text content so we need to
204242 // compare against its attribute value instead.
205243 const oldValue = el . tagName === 'OPTION' ? el . getAttribute ( 'value' ) : el . value
@@ -219,20 +257,19 @@ export function setValue(el: TargetElement, value: any): void {
219257 */
220258export function setText ( el : Text & { $txt ?: string } , value : string ) : void {
221259 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
260+ if ( el . nodeValue == value ) {
261+ el . $txt = value
262+ return
232263 }
233264
234- el . $txt = value
235- return
265+ ; ( __DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__ ) &&
266+ warn (
267+ `Hydration text mismatch in` ,
268+ el . parentNode ,
269+ `\n - rendered on server: ${ JSON . stringify ( ( el as Text ) . data ) } ` +
270+ `\n - expected on client: ${ JSON . stringify ( value ) } ` ,
271+ )
272+ logMismatchError ( )
236273 }
237274
238275 if ( el . $txt !== value ) {
@@ -258,22 +295,21 @@ export function setElementText(
258295 clientText = clientText . slice ( 1 )
259296 }
260297
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
298+ if ( el . textContent === clientText ) {
299+ el . $txt = clientText
300+ return
273301 }
274302
275- el . $txt = clientText
276- return
303+ if ( ! isMismatchAllowed ( el as Element , MismatchTypes . TEXT ) ) {
304+ ; ( __DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__ ) &&
305+ warn (
306+ `Hydration text content mismatch on` ,
307+ el ,
308+ `\n - rendered on server: ${ el . textContent } ` +
309+ `\n - expected on client: ${ clientText } ` ,
310+ )
311+ logMismatchError ( )
312+ }
277313 }
278314
279315 if ( el . $txt !== value ) {
@@ -285,22 +321,21 @@ export function setHtml(el: TargetElement, value: any): void {
285321 value = value == null ? '' : value
286322
287323 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
324+ if ( el . innerHTML === value ) {
325+ el . $html = value
326+ return
300327 }
301328
302- el . $html = value
303- return
329+ if ( ! isMismatchAllowed ( el , MismatchTypes . CHILDREN ) ) {
330+ if ( __DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__ ) {
331+ warn (
332+ `Hydration children mismatch on` ,
333+ el ,
334+ `\nServer rendered element contains different child nodes from client nodes.` ,
335+ )
336+ }
337+ logMismatchError ( )
338+ }
304339 }
305340
306341 if ( el . $html !== value ) {
@@ -384,13 +419,11 @@ export function optimizePropertyLookup(): void {
384419 ''
385420}
386421
387- function handleClassHydration (
422+ function classHasMismatch (
388423 el : TargetElement | any ,
389- value : any ,
390424 expected : string ,
391425 isIncremental : boolean ,
392- cacheKey : string ,
393- ) {
426+ ) : boolean {
394427 const actual = el . getAttribute ( 'class' )
395428 const actualClassSet = toClassSet ( actual || '' )
396429 const expectedClassSet = toClassSet ( expected )
@@ -403,27 +436,18 @@ function handleClassHydration(
403436 if ( hasMismatch ) {
404437 warnPropMismatch ( el , 'class' , MismatchTypes . CLASS , actual , expected )
405438 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- }
439+ return true
415440 }
416441
417- el [ cacheKey ] = expected
442+ return false
418443}
419444
420- function handleStyleHydration (
445+ function styleHasMismatch (
421446 el : TargetElement | any ,
422447 value : any ,
423448 normalizedValue : string | NormalizedStyle | undefined ,
424449 isIncremental : boolean ,
425- cacheKey : string ,
426- ) {
450+ ) : boolean {
427451 const actual = el . getAttribute ( 'style' )
428452 const actualStyleMap = toStyleMap ( actual || '' )
429453 const expected = isString ( value ) ? value : stringifyStyle ( normalizedValue )
@@ -446,8 +470,20 @@ function handleStyleHydration(
446470 if ( hasMismatch ) {
447471 warnPropMismatch ( el , 'style' , MismatchTypes . STYLE , actual , expected )
448472 logMismatchError ( )
449- patchStyle ( el , el [ cacheKey ] , ( el [ cacheKey ] = normalizedValue ) )
473+ return true
450474 }
451475
452- el [ cacheKey ] = normalizedValue
476+ return false
477+ }
478+
479+ function attributeHasMismatch ( el : any , key : string , value : any ) : boolean {
480+ if ( isValidHtmlOrSvgAttribute ( el , key ) ) {
481+ const { actual, expected } = getAttributeMismatch ( el , key , value )
482+ if ( actual !== expected ) {
483+ warnPropMismatch ( el , key , MismatchTypes . ATTRIBUTE , actual , expected )
484+ logMismatchError ( )
485+ return true
486+ }
487+ }
488+ return false
453489}
0 commit comments