Skip to content

Commit

Permalink
fix(hydration): escape css var name to avoid mismatch (#11739)
Browse files Browse the repository at this point in the history
close #11735
  • Loading branch information
edison1105 authored Sep 3, 2024
1 parent cb843e0 commit ca12e77
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 14 deletions.
12 changes: 0 additions & 12 deletions packages/compiler-sfc/src/script/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}`,
)
}
2 changes: 1 addition & 1 deletion packages/compiler-sfc/src/style/cssVars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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`

Expand Down
20 changes: 20 additions & 0 deletions packages/runtime-core/__tests__/hydration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down
6 changes: 5 additions & 1 deletion packages/runtime-core/src/hydration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
PatchFlags,
ShapeFlags,
def,
getEscapedCssVarName,
includeBooleanAttr,
isBooleanAttr,
isKnownHtmlAttr,
Expand Down Expand Up @@ -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) {
Expand Down
12 changes: 12 additions & 0 deletions packages/shared/src/escapeHtml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}`,
)
}

0 comments on commit ca12e77

Please sign in to comment.