mirror of
https://gitee.com/vuejs/vue.git
synced 2024-12-02 03:57:36 +08:00
fix(ssr): fix hydration mismatch with adjacent text node from slots
fix vuejs/vue-loader#974
This commit is contained in:
parent
94512f3e8c
commit
b080a14138
@ -42,20 +42,27 @@ function isTextNode (node): boolean {
|
|||||||
|
|
||||||
function normalizeArrayChildren (children: any, nestedIndex?: string): Array<VNode> {
|
function normalizeArrayChildren (children: any, nestedIndex?: string): Array<VNode> {
|
||||||
const res = []
|
const res = []
|
||||||
let i, c, last
|
let i, c, lastIndex, last
|
||||||
for (i = 0; i < children.length; i++) {
|
for (i = 0; i < children.length; i++) {
|
||||||
c = children[i]
|
c = children[i]
|
||||||
if (isUndef(c) || typeof c === 'boolean') continue
|
if (isUndef(c) || typeof c === 'boolean') continue
|
||||||
last = res[res.length - 1]
|
lastIndex = res.length - 1
|
||||||
|
last = res[lastIndex]
|
||||||
// nested
|
// nested
|
||||||
if (Array.isArray(c)) {
|
if (Array.isArray(c) && c.length > 0) {
|
||||||
res.push.apply(res, normalizeArrayChildren(c, `${nestedIndex || ''}_${i}`))
|
c = normalizeArrayChildren(c, `${nestedIndex || ''}_${i}`)
|
||||||
|
// merge adjacent text nodes
|
||||||
|
if (isTextNode(c[0]) && isTextNode(last)) {
|
||||||
|
res[lastIndex] = createTextVNode(last.text + (c[0]: any).text)
|
||||||
|
c.shift()
|
||||||
|
}
|
||||||
|
res.push.apply(res, c)
|
||||||
} else if (isPrimitive(c)) {
|
} else if (isPrimitive(c)) {
|
||||||
if (isTextNode(last)) {
|
if (isTextNode(last)) {
|
||||||
// merge adjacent text nodes
|
// merge adjacent text nodes
|
||||||
// this is necessary for SSR hydration because text nodes are
|
// this is necessary for SSR hydration because text nodes are
|
||||||
// essentially merged when rendered to HTML strings
|
// essentially merged when rendered to HTML strings
|
||||||
(last: any).text += String(c)
|
res[lastIndex] = createTextVNode(last.text + c)
|
||||||
} else if (c !== '') {
|
} else if (c !== '') {
|
||||||
// convert primitive to vnode
|
// convert primitive to vnode
|
||||||
res.push(createTextVNode(c))
|
res.push(createTextVNode(c))
|
||||||
@ -63,7 +70,7 @@ function normalizeArrayChildren (children: any, nestedIndex?: string): Array<VNo
|
|||||||
} else {
|
} else {
|
||||||
if (isTextNode(c) && isTextNode(last)) {
|
if (isTextNode(c) && isTextNode(last)) {
|
||||||
// merge adjacent text nodes
|
// merge adjacent text nodes
|
||||||
res[res.length - 1] = createTextVNode(last.text + c.text)
|
res[lastIndex] = createTextVNode(last.text + c.text)
|
||||||
} else {
|
} else {
|
||||||
// default key for nested array children (likely generated by v-for)
|
// default key for nested array children (likely generated by v-for)
|
||||||
if (isTrue(children._isVList) &&
|
if (isTrue(children._isVList) &&
|
||||||
|
@ -323,4 +323,23 @@ describe('vdom patch: hydration', () => {
|
|||||||
|
|
||||||
expect('not matching server-rendered content').toHaveBeenWarned()
|
expect('not matching server-rendered content').toHaveBeenWarned()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should hydrate with adjacent text nodes from array children (e.g. slots)', () => {
|
||||||
|
const dom = createMockSSRDOM('<div>foo</div> hello')
|
||||||
|
|
||||||
|
new Vue({
|
||||||
|
template: `<test>hello</test>`,
|
||||||
|
components: {
|
||||||
|
test: {
|
||||||
|
template: `
|
||||||
|
<div>
|
||||||
|
<div>foo</div>
|
||||||
|
<slot/>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).$mount(dom)
|
||||||
|
expect('not matching server-rendered content').not.toHaveBeenWarned()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user