Skip to content

Commit e585b0d

Browse files
committed
fix(ssr): avoid hydration mismatch warning for classes with different order
1 parent 048dffd commit e585b0d

File tree

2 files changed

+29
-3
lines changed

2 files changed

+29
-3
lines changed

packages/runtime-core/__tests__/hydration.spec.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1406,6 +1406,14 @@ describe('SSR hydration', () => {
14061406
mountWithHydration(`<div class="foo bar"></div>`, () =>
14071407
h('div', { class: 'foo bar' })
14081408
)
1409+
// SVG classes
1410+
mountWithHydration(`<svg class="foo bar"></svg>`, () =>
1411+
h('svg', { class: 'foo bar' })
1412+
)
1413+
// class with different order
1414+
mountWithHydration(`<div class="foo bar"></svg>`, () =>
1415+
h('div', { class: 'bar foo' })
1416+
)
14091417
expect(`Hydration class mismatch`).not.toHaveBeenWarned()
14101418
mountWithHydration(`<div class="foo bar"></div>`, () =>
14111419
h('div', { class: 'foo' })

packages/runtime-core/src/hydration.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -718,9 +718,11 @@ function propHasMismatch(el: Element, key: string, clientValue: any): boolean {
718718
let actual: any
719719
let expected: any
720720
if (key === 'class') {
721-
actual = el.getAttribute('class')
722-
expected = normalizeClass(clientValue)
723-
if (actual !== expected) {
721+
// classes might be in different order, but that doesn't affect cascade
722+
// so we just need to check if the class lists contain the same classes.
723+
actual = toClassSet(el.getAttribute('class') || '')
724+
expected = toClassSet(normalizeClass(clientValue))
725+
if (!isSetEqual(actual, expected)) {
724726
mismatchType = mismatchKey = `class`
725727
}
726728
} else if (key === 'style') {
@@ -765,3 +767,19 @@ function propHasMismatch(el: Element, key: string, clientValue: any): boolean {
765767
}
766768
return false
767769
}
770+
771+
function toClassSet(str: string): Set<string> {
772+
return new Set(str.trim().split(/\s+/))
773+
}
774+
775+
function isSetEqual(a: Set<string>, b: Set<string>): boolean {
776+
if (a.size !== b.size) {
777+
return false
778+
}
779+
for (const s of a) {
780+
if (!b.has(s)) {
781+
return false
782+
}
783+
}
784+
return true
785+
}

0 commit comments

Comments
 (0)