Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
55e9810
fix(hydration): Use escapeHTML when vnode is of text type
baiwusanyu-c Feb 22, 2023
4359f41
fix(hydration): added a unit test
baiwusanyu-c Feb 22, 2023
93b53e0
fix(hydration): updated
baiwusanyu-c Feb 23, 2023
a327625
Merge branch 'main' into bwsy/fix/hydrationText
baiwusanyu-c Mar 17, 2023
379500a
Merge branch 'main' into bwsy/fix/hydrationText
baiwusanyu-c Mar 20, 2023
7d72678
Merge branch 'main' into bwsy/fix/hydrationText
baiwusanyu-c Mar 23, 2023
993f827
Merge branch 'main' into bwsy/fix/hydrationText
baiwusanyu-c Mar 24, 2023
1a8020d
Merge branch 'main' into bwsy/fix/hydrationText
baiwusanyu-c Mar 27, 2023
e79f7b3
Merge branch 'main' into bwsy/fix/hydrationText
baiwusanyu-c Apr 6, 2023
10cd04c
Merge branch 'main' into bwsy/fix/hydrationText
baiwusanyu-c Apr 10, 2023
1d7b898
Merge branch 'main' into bwsy/fix/hydrationText
baiwusanyu-c Apr 11, 2023
c2f5be7
Merge branch 'main' into bwsy/fix/hydrationText
baiwusanyu-c Apr 14, 2023
062172f
Merge branch 'main' into bwsy/fix/hydrationText
baiwusanyu-c Apr 17, 2023
482108e
Merge branch 'main' into bwsy/fix/hydrationText
baiwusanyu-c Apr 19, 2023
c82c0db
Merge branch 'main' into bwsy/fix/hydrationText
baiwusanyu-c Apr 20, 2023
87af608
Merge branch 'main' into bwsy/fix/hydrationText
baiwusanyu-c Apr 25, 2023
5a2cb8e
Merge branch 'vuejs:main' into bwsy/fix/hydrationText
baiwusanyu-c May 4, 2023
159ac08
Merge branch 'main' into bwsy/fix/hydrationText
baiwusanyu-c May 9, 2023
7b4e391
Merge branch 'main' into bwsy/fix/hydrationText
baiwusanyu-c May 12, 2023
7918033
Merge branch 'main' into bwsy/fix/hydrationText
baiwusanyu-c May 16, 2023
d948a35
Merge branch 'main' into bwsy/fix/hydrationText
baiwusanyu-c May 17, 2023
89cd7a9
Merge branch 'main' into bwsy/fix/hydrationText
baiwusanyu-c May 23, 2023
034380e
updated code
baiwusanyu-c Jul 14, 2023
5091182
Merge branch 'main' into bwsy/fix/hydrationText
baiwusanyu-c Jul 17, 2023
8084a2f
feat(custom-element): rollback lock file
baiwusanyu-c Sep 15, 2023
ec4c1b8
chore: replace r\n\f\t and blank
baiwusanyu-c Sep 15, 2023
f26bd3d
chore: updated unit test
baiwusanyu-c Sep 15, 2023
6e10bbf
chore: rename file
baiwusanyu-c Sep 15, 2023
5b35e03
Merge remote-tracking branch 'origin/main' into bwsy/fix/hydrationText
baiwusanyu-c Nov 13, 2023
9e9e1bf
Merge remote-tracking branch 'origin/main' into bwsy/fix/hydrationText
baiwusanyu-c Jan 3, 2024
63a9a84
[autofix.ci] apply automated fixes
autofix-ci[bot] Jan 3, 2024
9b309af
Merge remote-tracking branch 'upstream/main' into bwsy/fix/hydrationText
Sep 5, 2024
7e667dc
Merge remote-tracking branch 'upstream/main' into bwsy/fix/hydrationText
Sep 5, 2024
d29f2b8
[autofix.ci] apply automated fixes
autofix-ci[bot] Sep 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions packages/runtime-core/__tests__/hydration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1710,6 +1710,23 @@ describe('SSR hydration', () => {
expect(`Hydration text content mismatch`).toHaveBeenWarned()
})

// #7775
test('use unescapeHtml when vnode is of text type', () => {
const { container: styleContainer } = mountWithHydration(
`<style>&quot;test&quot;\n\r</style>`,
() => h('style', '"test"'),
)
expect(styleContainer.innerHTML).toBe('<style>"test"</style>')
expect(`Hydration text content mismatch`).not.toHaveBeenWarned()

const { container: pContainer } = mountWithHydration(
`<p>&quot;test&quot;\n\r</p>`,
() => h('p', '"test"'),
)
expect(pContainer.innerHTML).toBe('<p>"test"</p>')
expect(`Hydration text content mismatch`).not.toHaveBeenWarned()
})

test('not enough children', () => {
const { container } = mountWithHydration(`<div></div>`, () =>
h('div', [h('span', 'foo'), h('span', 'bar')]),
Expand Down
37 changes: 25 additions & 12 deletions packages/runtime-core/src/hydration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
normalizeClass,
normalizeStyle,
stringifyStyle,
unescapeHtml,
} from '@vue/shared'
import { type RendererInternals, needTransition } from './renderer'
import { setRef } from './rendererTemplateRef'
Expand Down Expand Up @@ -180,17 +181,24 @@ export function createHydrationFunctions(
}
} else {
if ((node as Text).data !== vnode.children) {
;(__DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__) &&
warn(
`Hydration text mismatch in`,
node.parentNode,
`\n - rendered on server: ${JSON.stringify(
(node as Text).data,
)}` +
`\n - expected on client: ${JSON.stringify(vnode.children)}`,
)
logMismatchError()
;(node as Text).data = vnode.children as string
let dataContent = (node as Text).data.replace(/[\r\n]+/g, '')
let vnodeChildren = (vnode.children as string).replace(
/[\r\n]+/g,
'',
)
if (unescapeHtml(dataContent) !== unescapeHtml(vnodeChildren)) {
;(__DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__) &&
warn(
`Hydration text mismatch in`,
node.parentNode,
`\n - rendered on server: ${JSON.stringify(
(node as Text).data,
)}` +
`\n - expected on client: ${JSON.stringify(vnode.children)}`,
)
logMismatchError()
;(node as Text).data = vnode.children as string
}
}
nextNode = nextSibling(node)
}
Expand Down Expand Up @@ -441,7 +449,12 @@ export function createHydrationFunctions(
}
} else if (shapeFlag & ShapeFlags.TEXT_CHILDREN) {
if (el.textContent !== vnode.children) {
if (!isMismatchAllowed(el, MismatchTypes.TEXT)) {
let textContent = (el.textContent as string).replace(/[\r\n]+/g, '')
let vnodeChildren = (vnode.children as string).replace(/[\r\n]+/g, '')
if (
!isMismatchAllowed(el, MismatchTypes.TEXT) &&
unescapeHtml(textContent) !== unescapeHtml(vnodeChildren)
) {
;(__DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__) &&
warn(
`Hydration text content mismatch on`,
Expand Down
1 change: 1 addition & 0 deletions packages/shared/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export * from './normalizeProp'
export * from './domTagConfig'
export * from './domAttrConfig'
export * from './escapeHtml'
export * from './unescapeHtml'
export * from './looseEqual'
export * from './toDisplayString'
export * from './typeUtils'
24 changes: 24 additions & 0 deletions packages/shared/src/unescapeHtml.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const unescapeHtmlRE = /&\w+;|&#(\d+);/g
const UNESCAPE_HTML = {
'&lt;': '<',
'&gt;': '>',
'&amp;': '&',
'&quot;': '"',
'&#39;': "'",
}
export function unescapeHtml(s: string | null) {

Check failure on line 9 in packages/shared/src/unescapeHtml.ts

View workflow job for this annotation

GitHub Actions / continuous-release

Function must have an explicit return type annotation with --isolatedDeclarations.

Check failure on line 9 in packages/shared/src/unescapeHtml.ts

View workflow job for this annotation

GitHub Actions / test / lint-and-test-dts

Function must have an explicit return type annotation with --isolatedDeclarations.
if (!s) return s
return s.replace(unescapeHtmlRE, function ($0: string, $1: number) {
let c = UNESCAPE_HTML[$0 as keyof typeof UNESCAPE_HTML]
if (c === undefined) {
// Maybe is Entity Number
if (!isNaN($1)) {
c = String.fromCharCode($1 === 160 ? 32 : $1)
} else {
// Not Entity Number
c = $0
}
}
return c
})
}
Loading