diff --git a/packages/compiler-ssr/__tests__/ssrComponent.spec.ts b/packages/compiler-ssr/__tests__/ssrComponent.spec.ts
index 8efe67a5c..642289c29 100644
--- a/packages/compiler-ssr/__tests__/ssrComponent.spec.ts
+++ b/packages/compiler-ssr/__tests__/ssrComponent.spec.ts
@@ -219,11 +219,11 @@ describe('ssr: components', () => {
foo: ({ list }, _push, _parent, _scopeId) => {
if (_push) {
if (_ctx.ok) {
- _push(\`
\`)
+ _push(\`
\`)
_ssrRenderList(list, (i) => {
_push(\`\`)
})
- _push(\`
\`)
+ _push(\`
\`)
} else {
_push(\`\`)
}
@@ -242,11 +242,11 @@ describe('ssr: components', () => {
bar: ({ ok }, _push, _parent, _scopeId) => {
if (_push) {
if (ok) {
- _push(\`\`)
+ _push(\`
\`)
_ssrRenderList(_ctx.list, (i) => {
_push(\`\`)
})
- _push(\`
\`)
+ _push(\`
\`)
} else {
_push(\`\`)
}
@@ -283,7 +283,7 @@ describe('ssr: components', () => {
.toMatchInlineSnapshot(`
"
return function ssrRender(_ctx, _push, _parent) {
- _push(\`\`)
+ _push(\`\`)
}"
`)
@@ -305,7 +305,7 @@ describe('ssr: components', () => {
.toMatchInlineSnapshot(`
"
return function ssrRender(_ctx, _push, _parent) {
- _push(\`\`)
+ _push(\`\`)
}"
`)
})
diff --git a/packages/compiler-ssr/__tests__/ssrVFor.spec.ts b/packages/compiler-ssr/__tests__/ssrVFor.spec.ts
index a5b9ebd4c..eb301ab9b 100644
--- a/packages/compiler-ssr/__tests__/ssrVFor.spec.ts
+++ b/packages/compiler-ssr/__tests__/ssrVFor.spec.ts
@@ -6,11 +6,9 @@ describe('ssr: v-for', () => {
"const { ssrRenderList: _ssrRenderList } = require(\\"@vue/server-renderer\\")
return function ssrRender(_ctx, _push, _parent) {
- _push(\`\`)
_ssrRenderList(_ctx.list, (i) => {
_push(\`\`)
})
- _push(\`\`)
}"
`)
})
@@ -21,11 +19,9 @@ describe('ssr: v-for', () => {
"const { ssrRenderList: _ssrRenderList } = require(\\"@vue/server-renderer\\")
return function ssrRender(_ctx, _push, _parent) {
- _push(\`\`)
_ssrRenderList(_ctx.list, (i) => {
_push(\`foobar
\`)
})
- _push(\`\`)
}"
`)
})
@@ -41,9 +37,8 @@ describe('ssr: v-for', () => {
"const { ssrInterpolate: _ssrInterpolate, ssrRenderList: _ssrRenderList } = require(\\"@vue/server-renderer\\")
return function ssrRender(_ctx, _push, _parent) {
- _push(\`\`)
_ssrRenderList(_ctx.list, (row, i) => {
- _push(\`\`)
+ _push(\`
\`)
_ssrRenderList(row, (j) => {
_push(\`
\${
_ssrInterpolate(i)
@@ -51,9 +46,8 @@ describe('ssr: v-for', () => {
_ssrInterpolate(j)
}
\`)
})
- _push(\`
\`)
+ _push(\`
\`)
})
- _push(\`\`)
}"
`)
})
@@ -64,11 +58,9 @@ describe('ssr: v-for', () => {
"const { ssrInterpolate: _ssrInterpolate, ssrRenderList: _ssrRenderList } = require(\\"@vue/server-renderer\\")
return function ssrRender(_ctx, _push, _parent) {
- _push(\`\`)
_ssrRenderList(_ctx.list, (i) => {
- _push(\`\${_ssrInterpolate(i)}\`)
+ _push(\`\${_ssrInterpolate(i)}\`)
})
- _push(\`\`)
}"
`)
})
@@ -81,11 +73,9 @@ describe('ssr: v-for', () => {
"const { ssrInterpolate: _ssrInterpolate, ssrRenderList: _ssrRenderList } = require(\\"@vue/server-renderer\\")
return function ssrRender(_ctx, _push, _parent) {
- _push(\`\`)
_ssrRenderList(_ctx.list, (i) => {
_push(\`\${_ssrInterpolate(i)}\`)
})
- _push(\`\`)
}"
`)
})
@@ -99,15 +89,13 @@ describe('ssr: v-for', () => {
"const { ssrInterpolate: _ssrInterpolate, ssrRenderList: _ssrRenderList } = require(\\"@vue/server-renderer\\")
return function ssrRender(_ctx, _push, _parent) {
- _push(\`\`)
_ssrRenderList(_ctx.list, (i) => {
- _push(\`\${
+ _push(\`\${
_ssrInterpolate(i)
}\${
_ssrInterpolate(i + 1)
- }\`)
+ }\`)
})
- _push(\`\`)
}"
`)
})
@@ -123,11 +111,9 @@ describe('ssr: v-for', () => {
"const { ssrInterpolate: _ssrInterpolate, ssrRenderList: _ssrRenderList } = require(\\"@vue/server-renderer\\")
return function ssrRender(_ctx, _push, _parent) {
- _push(\`\`)
_ssrRenderList(_ctx.list, ({ foo }, index) => {
_push(\`\${_ssrInterpolate(foo + _ctx.bar + index)}
\`)
})
- _push(\`\`)
}"
`)
})
diff --git a/packages/compiler-ssr/__tests__/ssrVIf.spec.ts b/packages/compiler-ssr/__tests__/ssrVIf.spec.ts
index 4f9157456..8ea086797 100644
--- a/packages/compiler-ssr/__tests__/ssrVIf.spec.ts
+++ b/packages/compiler-ssr/__tests__/ssrVIf.spec.ts
@@ -80,7 +80,7 @@ describe('ssr: v-if', () => {
"
return function ssrRender(_ctx, _push, _parent) {
if (_ctx.foo) {
- _push(\`hello\`)
+ _push(\`hello\`)
} else {
_push(\`\`)
}
@@ -110,7 +110,7 @@ describe('ssr: v-if', () => {
"
return function ssrRender(_ctx, _push, _parent) {
if (_ctx.foo) {
- _push(\`hi
ho
\`)
+ _push(\`hi
ho
\`)
} else {
_push(\`\`)
}
@@ -126,11 +126,9 @@ describe('ssr: v-if', () => {
return function ssrRender(_ctx, _push, _parent) {
if (_ctx.foo) {
- _push(\`\`)
_ssrRenderList(_ctx.list, (i) => {
_push(\`\`)
})
- _push(\`\`)
} else {
_push(\`\`)
}
@@ -147,7 +145,7 @@ describe('ssr: v-if', () => {
"
return function ssrRender(_ctx, _push, _parent) {
if (_ctx.foo) {
- _push(\`hi
ho
\`)
+ _push(\`hi
ho
\`)
} else {
_push(\`\`)
}
diff --git a/packages/compiler-ssr/src/ssrCodegenTransform.ts b/packages/compiler-ssr/src/ssrCodegenTransform.ts
index 5afe4b55e..b9ef0c166 100644
--- a/packages/compiler-ssr/src/ssrCodegenTransform.ts
+++ b/packages/compiler-ssr/src/ssrCodegenTransform.ts
@@ -9,7 +9,6 @@ import {
ElementTypes,
createBlockStatement,
CompilerOptions,
- isText,
IfStatement,
CallExpression
} from '@vue/compiler-dom'
@@ -29,9 +28,7 @@ import { ssrProcessElement } from './transforms/ssrTransformElement'
export function ssrCodegenTransform(ast: RootNode, options: CompilerOptions) {
const context = createSSRTransformContext(ast, options)
- const isFragment =
- ast.children.length > 1 && ast.children.some(c => !isText(c))
- processChildren(ast.children, context, isFragment)
+ processChildren(ast.children, context)
ast.codegenNode = createBlockStatement(context.body)
// Finalize helpers.
@@ -107,12 +104,8 @@ function createChildContext(
export function processChildren(
children: TemplateChildNode[],
- context: SSRTransformContext,
- asFragment = false
+ context: SSRTransformContext
) {
- if (asFragment) {
- context.pushStringPart(``)
- }
for (let i = 0; i < children.length; i++) {
const child = children[i]
if (child.type === NodeTypes.ELEMENT) {
@@ -135,18 +128,14 @@ export function processChildren(
ssrProcessFor(child, context)
}
}
- if (asFragment) {
- context.pushStringPart(``)
- }
}
export function processChildrenAsStatement(
children: TemplateChildNode[],
parentContext: SSRTransformContext,
- asFragment = false,
withSlotScopeId = parentContext.withSlotScopeId
): BlockStatement {
const childContext = createChildContext(parentContext, withSlotScopeId)
- processChildren(children, childContext, asFragment)
+ processChildren(children, childContext)
return createBlockStatement(childContext.body)
}
diff --git a/packages/compiler-ssr/src/transforms/ssrTransformComponent.ts b/packages/compiler-ssr/src/transforms/ssrTransformComponent.ts
index e81e13a48..5a3ad978f 100644
--- a/packages/compiler-ssr/src/transforms/ssrTransformComponent.ts
+++ b/packages/compiler-ssr/src/transforms/ssrTransformComponent.ts
@@ -12,8 +12,6 @@ import {
FunctionExpression,
TemplateChildNode,
PORTAL,
- SUSPENSE,
- TRANSITION_GROUP,
createIfStatement,
createSimpleExpression,
getBaseTransformPreset,
@@ -135,14 +133,10 @@ export function ssrProcessComponent(
// this is a built-in component that fell-through.
// just render its children.
const component = componentTypeMap.get(node)!
-
if (component === PORTAL) {
return ssrProcessPortal(node, context)
}
-
- const needFragmentWrapper =
- component === SUSPENSE || component === TRANSITION_GROUP
- processChildren(node.children, context, needFragmentWrapper)
+ processChildren(node.children, context)
} else {
// finish up slot function expressions from the 1st pass.
const wipEntries = wipMap.get(node) || []
@@ -157,7 +151,6 @@ export function ssrProcessComponent(
processChildrenAsStatement(
children,
context,
- false,
true /* withSlotScopeId */
),
vnodeBranch
diff --git a/packages/compiler-ssr/src/transforms/ssrVFor.ts b/packages/compiler-ssr/src/transforms/ssrVFor.ts
index 1b6034ba8..1921b8f00 100644
--- a/packages/compiler-ssr/src/transforms/ssrVFor.ts
+++ b/packages/compiler-ssr/src/transforms/ssrVFor.ts
@@ -4,8 +4,7 @@ import {
processFor,
createCallExpression,
createFunctionExpression,
- createForLoopParams,
- NodeTypes
+ createForLoopParams
} from '@vue/compiler-dom'
import {
SSRTransformContext,
@@ -22,24 +21,14 @@ export const ssrTransformFor = createStructuralDirectiveTransform(
// This is called during the 2nd transform pass to construct the SSR-sepcific
// codegen nodes.
export function ssrProcessFor(node: ForNode, context: SSRTransformContext) {
- const needFragmentWrapper =
- node.children.length !== 1 || node.children[0].type !== NodeTypes.ELEMENT
const renderLoop = createFunctionExpression(
createForLoopParams(node.parseResult)
)
- renderLoop.body = processChildrenAsStatement(
- node.children,
- context,
- needFragmentWrapper
- )
-
- // v-for always renders a fragment
- context.pushStringPart(``)
+ renderLoop.body = processChildrenAsStatement(node.children, context)
context.pushStatement(
createCallExpression(context.helper(SSR_RENDER_LIST), [
node.source,
renderLoop
])
)
- context.pushStringPart(``)
}
diff --git a/packages/compiler-ssr/src/transforms/ssrVIf.ts b/packages/compiler-ssr/src/transforms/ssrVIf.ts
index aad7ad14d..d1c71e1d5 100644
--- a/packages/compiler-ssr/src/transforms/ssrVIf.ts
+++ b/packages/compiler-ssr/src/transforms/ssrVIf.ts
@@ -4,10 +4,7 @@ import {
IfNode,
createIfStatement,
createBlockStatement,
- createCallExpression,
- IfBranchNode,
- BlockStatement,
- NodeTypes
+ createCallExpression
} from '@vue/compiler-dom'
import {
SSRTransformContext,
@@ -26,14 +23,17 @@ export function ssrProcessIf(node: IfNode, context: SSRTransformContext) {
const [rootBranch] = node.branches
const ifStatement = createIfStatement(
rootBranch.condition!,
- processIfBranch(rootBranch, context)
+ processChildrenAsStatement(rootBranch.children, context)
)
context.pushStatement(ifStatement)
let currentIf = ifStatement
for (let i = 1; i < node.branches.length; i++) {
const branch = node.branches[i]
- const branchBlockStatement = processIfBranch(branch, context)
+ const branchBlockStatement = processChildrenAsStatement(
+ branch.children,
+ context
+ )
if (branch.condition) {
// else-if
currentIf = currentIf.alternate = createIfStatement(
@@ -52,15 +52,3 @@ export function ssrProcessIf(node: IfNode, context: SSRTransformContext) {
])
}
}
-
-function processIfBranch(
- branch: IfBranchNode,
- context: SSRTransformContext
-): BlockStatement {
- const { children } = branch
- const needFragmentWrapper =
- (children.length !== 1 || children[0].type !== NodeTypes.ELEMENT) &&
- // optimize away nested fragments when the only child is a ForNode
- !(children.length === 1 && children[0].type === NodeTypes.FOR)
- return processChildrenAsStatement(children, context, needFragmentWrapper)
-}
diff --git a/packages/runtime-core/__tests__/apiOptions.spec.ts b/packages/runtime-core/__tests__/apiOptions.spec.ts
index a7d5ca6b9..36f361740 100644
--- a/packages/runtime-core/__tests__/apiOptions.spec.ts
+++ b/packages/runtime-core/__tests__/apiOptions.spec.ts
@@ -281,7 +281,7 @@ describe('api: options', () => {
}
} as any
- expect(renderToString(h(Root))).toBe(`1112`)
+ expect(renderToString(h(Root))).toBe(`1112`)
})
test('lifecycle', async () => {
diff --git a/packages/runtime-core/__tests__/components/Portal.spec.ts b/packages/runtime-core/__tests__/components/Portal.spec.ts
index b71d5d6fb..52e1676a5 100644
--- a/packages/runtime-core/__tests__/components/Portal.spec.ts
+++ b/packages/runtime-core/__tests__/components/Portal.spec.ts
@@ -6,7 +6,6 @@ import {
defineComponent,
Portal,
Text,
- Fragment,
ref,
nextTick,
TestElement,
@@ -19,12 +18,10 @@ describe('renderer: portal', () => {
const target = nodeOps.createElement('div')
const root = nodeOps.createElement('div')
- const Comp = defineComponent(() => () =>
- h(Fragment, [
- h(Portal, { target }, h('div', 'teleported')),
- h('div', 'root')
- ])
- )
+ const Comp = defineComponent(() => () => [
+ h(Portal, { target }, h('div', 'teleported')),
+ h('div', 'root')
+ ])
render(h(Comp), root)
expect(serializeInner(root)).toMatchSnapshot()
@@ -37,12 +34,10 @@ describe('renderer: portal', () => {
const target = ref(targetA)
const root = nodeOps.createElement('div')
- const Comp = defineComponent(() => () =>
- h(Fragment, [
- h(Portal, { target: target.value }, h('div', 'teleported')),
- h('div', 'root')
- ])
- )
+ const Comp = defineComponent(() => () => [
+ h(Portal, { target: target.value }, h('div', 'teleported')),
+ h('div', 'root')
+ ])
render(h(Comp), root)
expect(serializeInner(root)).toMatchSnapshot()
diff --git a/packages/runtime-core/__tests__/components/Suspense.spec.ts b/packages/runtime-core/__tests__/components/Suspense.spec.ts
index 6a115e39c..119144068 100644
--- a/packages/runtime-core/__tests__/components/Suspense.spec.ts
+++ b/packages/runtime-core/__tests__/components/Suspense.spec.ts
@@ -451,14 +451,14 @@ describe('Suspense', () => {
await deps[0]
await nextTick()
expect(serializeInner(root)).toBe(
- `async outer
fallback inner
`
+ `async outer
fallback inner
`
)
expect(calls).toEqual([`outer mounted`])
await Promise.all(deps)
await nextTick()
expect(serializeInner(root)).toBe(
- `async outer
async inner
`
+ `async outer
async inner
`
)
expect(calls).toEqual([`outer mounted`, `inner mounted`])
})
@@ -522,7 +522,7 @@ describe('Suspense', () => {
await Promise.all(deps)
await nextTick()
expect(serializeInner(root)).toBe(
- `async outer
async inner
`
+ `async outer
async inner
`
)
expect(calls).toEqual([`inner mounted`, `outer mounted`])
})
@@ -663,7 +663,7 @@ describe('Suspense', () => {
await deps[3]
await nextTick()
expect(serializeInner(root)).toBe(
- `nested fallback
root async
`
+ `nested fallback
root async
`
)
expect(calls).toEqual([0, 1, 3])
@@ -674,7 +674,7 @@ describe('Suspense', () => {
await Promise.all(deps)
await nextTick()
expect(serializeInner(root)).toBe(
- `nested changed
root async
`
+ `nested changed
root async
`
)
expect(calls).toEqual([0, 1, 3, 2])
@@ -682,7 +682,7 @@ describe('Suspense', () => {
msg.value = 'nested changed again'
await nextTick()
expect(serializeInner(root)).toBe(
- `nested changed again
root async
`
+ `nested changed again
root async
`
)
})
@@ -717,7 +717,7 @@ describe('Suspense', () => {
await deps[0]
await nextTick()
- expect(serializeInner(root)).toBe(`Child A
`)
+ expect(serializeInner(root)).toBe(`Child A
`)
toggle.value = true
await nextTick()
@@ -725,9 +725,7 @@ describe('Suspense', () => {
await deps[1]
await nextTick()
- expect(serializeInner(root)).toBe(
- `Child A
Child B
`
- )
+ expect(serializeInner(root)).toBe(`Child A
Child B
`)
})
test.todo('portal inside suspense')
diff --git a/packages/runtime-core/__tests__/components/__snapshots__/Portal.spec.ts.snap b/packages/runtime-core/__tests__/components/__snapshots__/Portal.spec.ts.snap
index 77d48c3cc..4a47a5858 100644
--- a/packages/runtime-core/__tests__/components/__snapshots__/Portal.spec.ts.snap
+++ b/packages/runtime-core/__tests__/components/__snapshots__/Portal.spec.ts.snap
@@ -6,18 +6,18 @@ exports[`renderer: portal should update children 2`] = `""`;
exports[`renderer: portal should update children 3`] = `"teleported"`;
-exports[`renderer: portal should update target 1`] = `"root
"`;
+exports[`renderer: portal should update target 1`] = `"root
"`;
exports[`renderer: portal should update target 2`] = `"teleported
"`;
exports[`renderer: portal should update target 3`] = `""`;
-exports[`renderer: portal should update target 4`] = `"root
"`;
+exports[`renderer: portal should update target 4`] = `"root
"`;
exports[`renderer: portal should update target 5`] = `""`;
exports[`renderer: portal should update target 6`] = `"teleported
"`;
-exports[`renderer: portal should work 1`] = `"root
"`;
+exports[`renderer: portal should work 1`] = `"root
"`;
exports[`renderer: portal should work 2`] = `"teleported
"`;
diff --git a/packages/runtime-core/__tests__/hmr.spec.ts b/packages/runtime-core/__tests__/hmr.spec.ts
index 4da8d0db4..08b734fa3 100644
--- a/packages/runtime-core/__tests__/hmr.spec.ts
+++ b/packages/runtime-core/__tests__/hmr.spec.ts
@@ -60,13 +60,13 @@ describe('hot module replacement', () => {
createRecord(parentId, Parent)
render(h(Parent), root)
- expect(serializeInner(root)).toBe(`00
`)
+ expect(serializeInner(root)).toBe(`00
`)
// Perform some state change. This change should be preserved after the
// re-render!
triggerEvent(root.children[0] as TestElement, 'click')
await nextTick()
- expect(serializeInner(root)).toBe(`11
`)
+ expect(serializeInner(root)).toBe(`11
`)
// Update text while preserving state
rerender(
@@ -75,7 +75,7 @@ describe('hot module replacement', () => {
`{{ count }}!{{ count }}
`
)
)
- expect(serializeInner(root)).toBe(`1!1
`)
+ expect(serializeInner(root)).toBe(`1!1
`)
// Should force child update on slot content change
rerender(
@@ -84,7 +84,7 @@ describe('hot module replacement', () => {
`{{ count }}!{{ count }}!
`
)
)
- expect(serializeInner(root)).toBe(`1!1!
`)
+ expect(serializeInner(root)).toBe(`1!1!
`)
// Should force update element children despite block optimization
rerender(
@@ -95,9 +95,7 @@ describe('hot module replacement', () => {
`
)
)
- expect(serializeInner(root)).toBe(
- `111!
`
- )
+ expect(serializeInner(root)).toBe(`111!
`)
// Should force update child slot elements
rerender(
@@ -108,7 +106,7 @@ describe('hot module replacement', () => {
`
)
)
- expect(serializeInner(root)).toBe(`1
`)
+ expect(serializeInner(root)).toBe(`1
`)
})
test('reload', async () => {
diff --git a/packages/runtime-core/__tests__/rendererAttrsFallthrough.spec.ts b/packages/runtime-core/__tests__/rendererAttrsFallthrough.spec.ts
index fe34eee60..136a01256 100644
--- a/packages/runtime-core/__tests__/rendererAttrsFallthrough.spec.ts
+++ b/packages/runtime-core/__tests__/rendererAttrsFallthrough.spec.ts
@@ -322,9 +322,7 @@ describe('attribute fallthrough', () => {
render(h(Parent), root)
expect(`Extraneous non-props attributes`).not.toHaveBeenWarned()
- expect(root.innerHTML).toBe(
- ``
- )
+ expect(root.innerHTML).toBe(``)
})
it('should not warn when context.attrs is used during render', () => {
@@ -346,8 +344,6 @@ describe('attribute fallthrough', () => {
render(h(Parent), root)
expect(`Extraneous non-props attributes`).not.toHaveBeenWarned()
- expect(root.innerHTML).toBe(
- ``
- )
+ expect(root.innerHTML).toBe(``)
})
})
diff --git a/packages/runtime-core/__tests__/rendererFragment.spec.ts b/packages/runtime-core/__tests__/rendererFragment.spec.ts
index 091ef7a29..687bcbab2 100644
--- a/packages/runtime-core/__tests__/rendererFragment.spec.ts
+++ b/packages/runtime-core/__tests__/rendererFragment.spec.ts
@@ -25,10 +25,11 @@ describe('renderer: fragment', () => {
const root = nodeOps.createElement('div')
render(h(App), root)
- expect(serializeInner(root)).toBe(`one
two`)
+ expect(serializeInner(root)).toBe(`one
two`)
expect(root.children.length).toBe(4)
expect(root.children[0]).toMatchObject({
- type: NodeTypes.COMMENT
+ type: NodeTypes.TEXT,
+ text: ''
})
expect(root.children[1]).toMatchObject({
type: NodeTypes.ELEMENT,
@@ -43,7 +44,8 @@ describe('renderer: fragment', () => {
text: 'two'
})
expect(root.children[3]).toMatchObject({
- type: NodeTypes.COMMENT
+ type: NodeTypes.TEXT,
+ text: ''
})
})
@@ -51,7 +53,7 @@ describe('renderer: fragment', () => {
const root = nodeOps.createElement('div')
render(h('div', [h(Fragment, [h('div', 'one'), 'two'])]), root)
const parent = root.children[0] as TestElement
- expect(serializeInner(parent)).toBe(`one
two`)
+ expect(serializeInner(parent)).toBe(`one
two`)
})
it('patch fragment children (manual, keyed)', () => {
@@ -60,18 +62,14 @@ describe('renderer: fragment', () => {
h(Fragment, [h('div', { key: 1 }, 'one'), h('div', { key: 2 }, 'two')]),
root
)
- expect(serializeInner(root)).toBe(
- `one
two
`
- )
+ expect(serializeInner(root)).toBe(`one
two
`)
resetOps()
render(
h(Fragment, [h('div', { key: 2 }, 'two'), h('div', { key: 1 }, 'one')]),
root
)
- expect(serializeInner(root)).toBe(
- `two
one
`
- )
+ expect(serializeInner(root)).toBe(`two
one
`)
const ops = dumpOps()
// should be moving nodes instead of re-creating or patching them
expect(ops).toMatchObject([
@@ -84,15 +82,11 @@ describe('renderer: fragment', () => {
it('patch fragment children (manual, unkeyed)', () => {
const root = nodeOps.createElement('div')
render(h(Fragment, [h('div', 'one'), h('div', 'two')]), root)
- expect(serializeInner(root)).toBe(
- `one
two
`
- )
+ expect(serializeInner(root)).toBe(`one
two
`)
resetOps()
render(h(Fragment, [h('div', 'two'), h('div', 'one')]), root)
- expect(serializeInner(root)).toBe(
- `two
one
`
- )
+ expect(serializeInner(root)).toBe(`two
one
`)
const ops = dumpOps()
// should be patching nodes instead of moving or re-creating them
expect(ops).toMatchObject([
@@ -119,7 +113,7 @@ describe('renderer: fragment', () => {
),
root
)
- expect(serializeInner(root)).toBe(`one
two`)
+ expect(serializeInner(root)).toBe(`one
two`)
render(
createVNode(
@@ -134,7 +128,7 @@ describe('renderer: fragment', () => {
),
root
)
- expect(serializeInner(root)).toBe(`foo
barbaz`)
+ expect(serializeInner(root)).toBe(`foo
barbaz`)
})
it('patch fragment children (compiler generated, keyed)', () => {
@@ -149,9 +143,7 @@ describe('renderer: fragment', () => {
),
root
)
- expect(serializeInner(root)).toBe(
- `one
two
`
- )
+ expect(serializeInner(root)).toBe(`one
two
`)
resetOps()
render(
@@ -163,9 +155,7 @@ describe('renderer: fragment', () => {
),
root
)
- expect(serializeInner(root)).toBe(
- `two
one
`
- )
+ expect(serializeInner(root)).toBe(`two
one
`)
const ops = dumpOps()
// should be moving nodes instead of re-creating or patching them
expect(ops).toMatchObject([
@@ -188,7 +178,7 @@ describe('renderer: fragment', () => {
root
)
expect(serializeInner(root)).toBe(
- ``
+ ``
)
resetOps()
@@ -203,7 +193,7 @@ describe('renderer: fragment', () => {
root
)
expect(serializeInner(root)).toBe(
- ``
+ ``
)
const ops = dumpOps()
// should be moving nodes instead of re-creating them
@@ -213,10 +203,10 @@ describe('renderer: fragment', () => {
// 2. move entire fragment, including anchors
// not the most efficient move, but this case is super rare
// and optimizing for this special case complicates the algo quite a bit
- { type: NodeOpTypes.INSERT, targetNode: { type: 'comment' } },
+ { type: NodeOpTypes.INSERT, targetNode: { type: 'text', text: '' } },
{ type: NodeOpTypes.INSERT, targetNode: { type: 'element' } },
{ type: NodeOpTypes.INSERT, targetNode: { type: 'element' } },
- { type: NodeOpTypes.INSERT, targetNode: { type: 'comment' } }
+ { type: NodeOpTypes.INSERT, targetNode: { type: 'text', text: '' } }
])
})
@@ -234,7 +224,7 @@ describe('renderer: fragment', () => {
root
)
expect(serializeInner(root)).toBe(
- `outer
one
two
`
+ `outer
one
two
`
)
resetOps()
@@ -249,16 +239,16 @@ describe('renderer: fragment', () => {
root
)
expect(serializeInner(root)).toBe(
- `two
one
outer
`
+ `two
one
outer
`
)
const ops = dumpOps()
// should be moving nodes instead of re-creating them
expect(ops).toMatchObject([
{ type: NodeOpTypes.INSERT, targetNode: { type: 'element' } },
- { type: NodeOpTypes.INSERT, targetNode: { type: 'comment' } },
+ { type: NodeOpTypes.INSERT, targetNode: { type: 'text', text: '' } },
{ type: NodeOpTypes.INSERT, targetNode: { type: 'element' } },
{ type: NodeOpTypes.INSERT, targetNode: { type: 'element' } },
- { type: NodeOpTypes.INSERT, targetNode: { type: 'comment' } }
+ { type: NodeOpTypes.INSERT, targetNode: { type: 'text', text: '' } }
])
// should properly remove nested fragments
diff --git a/packages/runtime-core/src/hydration.ts b/packages/runtime-core/src/hydration.ts
index 8861a1984..ffe71ad36 100644
--- a/packages/runtime-core/src/hydration.ts
+++ b/packages/runtime-core/src/hydration.ts
@@ -24,7 +24,7 @@ export type RootHydrateFunction = (
// passed in via arguments.
export function createHydrationFunctions({
mt: mountComponent,
- o: { patchProp }
+ o: { patchProp, createText }
}: RendererInternals) {
const hydrate: RootHydrateFunction = (vnode, container) => {
if (__DEV__ && !container.hasChildNodes()) {
@@ -40,7 +40,7 @@ export function createHydrationFunctions({
node: Node,
vnode: VNode,
parentComponent: ComponentInternalInstance | null = null
- ): Node | null | undefined => {
+ ): Node | null => {
const { type, shapeFlag } = vnode
vnode.el = node
switch (type) {
@@ -49,14 +49,15 @@ export function createHydrationFunctions({
case Static:
return node.nextSibling
case Fragment:
- const anchor = (vnode.anchor = hydrateChildren(
- node.nextSibling,
+ const parent = node.parentNode!
+ parent.insertBefore((vnode.el = createText('')), node)
+ const next = hydrateChildren(
+ node,
vnode.children as VNode[],
parentComponent
- )!)
- // TODO handle potential hydration error if fragment didn't get
- // back anchor as expected.
- return anchor.nextSibling
+ )
+ parent.insertBefore((vnode.anchor = createText('')), next)
+ return next
default:
if (shapeFlag & ShapeFlags.ELEMENT) {
return hydrateElement(node as Element, vnode, parentComponent)
@@ -75,6 +76,7 @@ export function createHydrationFunctions({
} else if (__DEV__) {
warn('Invalid HostVNode type:', type, `(${typeof type})`)
}
+ return null
}
}
@@ -130,10 +132,10 @@ export function createHydrationFunctions({
}
const hydrateChildren = (
- node: Node | null | undefined,
+ node: Node | null,
vnodes: VNode[],
parentComponent: ComponentInternalInstance | null
- ): Node | null | undefined => {
+ ): Node | null => {
for (let i = 0; node != null && i < vnodes.length; i++) {
// TODO can skip normalizeVNode in optimized mode
// (need hint on rendered markup?)
diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts
index a92708633..3e0cef8c1 100644
--- a/packages/runtime-core/src/renderer.ts
+++ b/packages/runtime-core/src/renderer.ts
@@ -126,7 +126,6 @@ export interface RendererInternals {
pbc: PatchBlockChildrenFn
n: NextFn
o: RendererOptions
- c: ProcessTextOrCommentFn
}
// These functions are created inside a closure and therefore their types cannot
@@ -845,8 +844,6 @@ function baseCreateRenderer<
}
}
- let devFragmentID = 0
-
const processFragment = (
n1: HostVNode | null,
n2: HostVNode,
@@ -857,13 +854,8 @@ function baseCreateRenderer<
isSVG: boolean,
optimized: boolean
) => {
- const showID = __DEV__ && !__TEST__
- const fragmentStartAnchor = (n2.el = n1
- ? n1.el
- : hostCreateComment(showID ? `fragment-${devFragmentID}-start` : ''))!
- const fragmentEndAnchor = (n2.anchor = n1
- ? n1.anchor
- : hostCreateComment(showID ? `fragment-${devFragmentID}-end` : ''))!
+ const fragmentStartAnchor = (n2.el = n1 ? n1.el : hostCreateText(''))!
+ const fragmentEndAnchor = (n2.anchor = n1 ? n1.anchor : hostCreateText(''))!
let { patchFlag, dynamicChildren } = n2
if (patchFlag > 0) {
@@ -878,9 +870,6 @@ function baseCreateRenderer<
}
if (n1 == null) {
- if (showID) {
- devFragmentID++
- }
hostInsert(fragmentStartAnchor, container, anchor)
hostInsert(fragmentEndAnchor, container, anchor)
// a fragment can only have array children
@@ -1864,7 +1853,6 @@ function baseCreateRenderer<
pc: patchChildren,
pbc: patchBlockChildren,
n: getNextHostNode,
- c: processCommentNode,
o: options
}
diff --git a/packages/server-renderer/__tests__/renderToString.spec.ts b/packages/server-renderer/__tests__/renderToString.spec.ts
index c8bb79c87..730f7a145 100644
--- a/packages/server-renderer/__tests__/renderToString.spec.ts
+++ b/packages/server-renderer/__tests__/renderToString.spec.ts
@@ -262,7 +262,7 @@ describe('ssr: renderToString', () => {
)
).toBe(
`parent
` +
- `from slot` +
+ `from slot` +
`
`
)
@@ -277,7 +277,7 @@ describe('ssr: renderToString', () => {
}
})
)
- ).toBe(``)
+ ).toBe(``)
})
test('nested components with vnode slots', async () => {
@@ -321,7 +321,7 @@ describe('ssr: renderToString', () => {
)
).toBe(
`parent
` +
- `from slot` +
+ `from slot` +
`
`
)
})
@@ -339,7 +339,7 @@ describe('ssr: renderToString', () => {
expect(await renderToString(app)).toBe(
`parent
` +
- `from slot` +
+ `from slot` +
`
`
)
})
@@ -461,9 +461,7 @@ describe('ssr: renderToString', () => {
createCommentVNode('qux')
])
)
- ).toBe(
- `foobarbaz
`
- )
+ ).toBe(`foobarbaz
`)
})
test('void elements', async () => {
diff --git a/packages/server-renderer/src/helpers/ssrRenderSlot.ts b/packages/server-renderer/src/helpers/ssrRenderSlot.ts
index d8826a03e..1aae61f2b 100644
--- a/packages/server-renderer/src/helpers/ssrRenderSlot.ts
+++ b/packages/server-renderer/src/helpers/ssrRenderSlot.ts
@@ -19,8 +19,6 @@ export function ssrRenderSlot(
parentComponent: ComponentInternalInstance
) {
const slotFn = slots[slotName]
- // template-compiled slots are always rendered as fragments
- push(``)
if (slotFn) {
if (slotFn.length > 1) {
// only ssr-optimized slot fns accept more than 1 arguments
@@ -33,5 +31,4 @@ export function ssrRenderSlot(
} else if (fallbackRenderFn) {
fallbackRenderFn()
}
- push(``)
}
diff --git a/packages/server-renderer/src/renderToString.ts b/packages/server-renderer/src/renderToString.ts
index 14c041c65..5b5ecc4d5 100644
--- a/packages/server-renderer/src/renderToString.ts
+++ b/packages/server-renderer/src/renderToString.ts
@@ -238,9 +238,7 @@ function renderVNode(
push(children ? `` : ``)
break
case Fragment:
- push(``)
renderVNodeChildren(push, children as VNodeArrayChildren, parentComponent)
- push(``)
break
default:
if (shapeFlag & ShapeFlags.ELEMENT) {