diff --git a/src/core/vdom/helpers/normalize-children.js b/src/core/vdom/helpers/normalize-children.js index 16810844973..d0010c92ca8 100644 --- a/src/core/vdom/helpers/normalize-children.js +++ b/src/core/vdom/helpers/normalize-children.js @@ -42,20 +42,27 @@ function isTextNode (node): boolean { function normalizeArrayChildren (children: any, nestedIndex?: string): Array { const res = [] - let i, c, last + let i, c, lastIndex, last for (i = 0; i < children.length; i++) { c = children[i] if (isUndef(c) || typeof c === 'boolean') continue - last = res[res.length - 1] + lastIndex = res.length - 1 + last = res[lastIndex] // nested - if (Array.isArray(c)) { - res.push.apply(res, normalizeArrayChildren(c, `${nestedIndex || ''}_${i}`)) + if (Array.isArray(c) && c.length > 0) { + 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)) { if (isTextNode(last)) { // merge adjacent text nodes // this is necessary for SSR hydration because text nodes are // essentially merged when rendered to HTML strings - (last: any).text += String(c) + res[lastIndex] = createTextVNode(last.text + c) } else if (c !== '') { // convert primitive to vnode res.push(createTextVNode(c)) @@ -63,7 +70,7 @@ function normalizeArrayChildren (children: any, nestedIndex?: string): Array { expect('not matching server-rendered content').toHaveBeenWarned() }) + + it('should hydrate with adjacent text nodes from array children (e.g. slots)', () => { + const dom = createMockSSRDOM('
foo
hello') + + new Vue({ + template: `hello`, + components: { + test: { + template: ` +
+
foo
+ +
+ ` + } + } + }).$mount(dom) + expect('not matching server-rendered content').not.toHaveBeenWarned() + }) })