fix(hydration): escape css var name to avoid mismatch (#11739)

close #11735
This commit is contained in:
edison 2024-09-03 08:25:00 +08:00 committed by GitHub
parent cb843e0be3
commit ca12e776bc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 38 additions and 14 deletions

View File

@ -121,15 +121,3 @@ export const propNameEscapeSymbolsRE: RegExp =
export function getEscapedPropName(key: string): string {
return propNameEscapeSymbolsRE.test(key) ? JSON.stringify(key) : key
}
export const cssVarNameEscapeSymbolsRE: RegExp =
/[ !"#$%&'()*+,./:;<=>?@[\\\]^`{|}~]/g
export function getEscapedCssVarName(
key: string,
doubleEscape: boolean,
): string {
return key.replace(cssVarNameEscapeSymbolsRE, s =>
doubleEscape ? `\\\\${s}` : `\\${s}`,
)
}

View File

@ -8,9 +8,9 @@ import {
processExpression,
} from '@vue/compiler-dom'
import type { SFCDescriptor } from '../parse'
import { getEscapedCssVarName } from '../script/utils'
import type { PluginCreator } from 'postcss'
import hash from 'hash-sum'
import { getEscapedCssVarName } from '@vue/shared'
export const CSS_VARS_HELPER = `useCssVars`

View File

@ -2021,6 +2021,26 @@ describe('SSR hydration', () => {
app.mount(container)
expect(`Hydration style mismatch`).not.toHaveBeenWarned()
})
test('escape css var name', () => {
const container = document.createElement('div')
container.innerHTML = `<div style="padding: 4px;--foo\\.bar:red;"></div>`
const app = createSSRApp({
setup() {
useCssVars(() => ({
'foo.bar': 'red',
}))
return () => h(Child)
},
})
const Child = {
setup() {
return () => h('div', { style: 'padding: 4px' })
},
}
app.mount(container)
expect(`Hydration style mismatch`).not.toHaveBeenWarned()
})
})
describe('data-allow-mismatch', () => {

View File

@ -18,6 +18,7 @@ import {
PatchFlags,
ShapeFlags,
def,
getEscapedCssVarName,
includeBooleanAttr,
isBooleanAttr,
isKnownHtmlAttr,
@ -915,7 +916,10 @@ function resolveCssVars(
) {
const cssVars = instance.getCssVars()
for (const key in cssVars) {
expectedMap.set(`--${key}`, String(cssVars[key]))
expectedMap.set(
`--${getEscapedCssVarName(key, false)}`,
String(cssVars[key]),
)
}
}
if (vnode === root && instance.parent) {

View File

@ -50,3 +50,15 @@ const commentStripRE = /^-?>|<!--|-->|--!>|<!-$/g
export function escapeHtmlComment(src: string): string {
return src.replace(commentStripRE, '')
}
export const cssVarNameEscapeSymbolsRE: RegExp =
/[ !"#$%&'()*+,./:;<=>?@[\\\]^`{|}~]/g
export function getEscapedCssVarName(
key: string,
doubleEscape: boolean,
): string {
return key.replace(cssVarNameEscapeSymbolsRE, s =>
doubleEscape ? `\\\\${s}` : `\\${s}`,
)
}