]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
refactor(fragments): remove visible anchors for fragments
authorEvan You <yyx990803@gmail.com>
Wed, 26 Feb 2020 21:32:06 +0000 (16:32 -0500)
committerEvan You <yyx990803@gmail.com>
Wed, 26 Feb 2020 21:32:06 +0000 (16:32 -0500)
19 files changed:
packages/compiler-ssr/__tests__/ssrComponent.spec.ts
packages/compiler-ssr/__tests__/ssrVFor.spec.ts
packages/compiler-ssr/__tests__/ssrVIf.spec.ts
packages/compiler-ssr/src/ssrCodegenTransform.ts
packages/compiler-ssr/src/transforms/ssrTransformComponent.ts
packages/compiler-ssr/src/transforms/ssrVFor.ts
packages/compiler-ssr/src/transforms/ssrVIf.ts
packages/runtime-core/__tests__/apiOptions.spec.ts
packages/runtime-core/__tests__/components/Portal.spec.ts
packages/runtime-core/__tests__/components/Suspense.spec.ts
packages/runtime-core/__tests__/components/__snapshots__/Portal.spec.ts.snap
packages/runtime-core/__tests__/hmr.spec.ts
packages/runtime-core/__tests__/rendererAttrsFallthrough.spec.ts
packages/runtime-core/__tests__/rendererFragment.spec.ts
packages/runtime-core/src/hydration.ts
packages/runtime-core/src/renderer.ts
packages/server-renderer/__tests__/renderToString.spec.ts
packages/server-renderer/src/helpers/ssrRenderSlot.ts
packages/server-renderer/src/renderToString.ts

index 8efe67a5c9a88c9cfe710517253935316a3dbc42..642289c29a642043ee2bde3205d2a66d63ad9315 100644 (file)
@@ -219,11 +219,11 @@ describe('ssr: components', () => {
             foo: ({ list }, _push, _parent, _scopeId) => {
               if (_push) {
                 if (_ctx.ok) {
-                  _push(\`<div\${_scopeId}><!---->\`)
+                  _push(\`<div\${_scopeId}>\`)
                   _ssrRenderList(list, (i) => {
                     _push(\`<span\${_scopeId}></span>\`)
                   })
-                  _push(\`<!----></div>\`)
+                  _push(\`</div>\`)
                 } else {
                   _push(\`<!---->\`)
                 }
@@ -242,11 +242,11 @@ describe('ssr: components', () => {
             bar: ({ ok }, _push, _parent, _scopeId) => {
               if (_push) {
                 if (ok) {
-                  _push(\`<div\${_scopeId}><!---->\`)
+                  _push(\`<div\${_scopeId}>\`)
                   _ssrRenderList(_ctx.list, (i) => {
                     _push(\`<span\${_scopeId}></span>\`)
                   })
-                  _push(\`<!----></div>\`)
+                  _push(\`</div>\`)
                 } else {
                   _push(\`<!---->\`)
                 }
@@ -283,7 +283,7 @@ describe('ssr: components', () => {
         .toMatchInlineSnapshot(`
         "
         return function ssrRender(_ctx, _push, _parent) {
-          _push(\`<!----><div></div><!---->\`)
+          _push(\`<div></div>\`)
         }"
       `)
 
@@ -305,7 +305,7 @@ describe('ssr: components', () => {
         .toMatchInlineSnapshot(`
         "
         return function ssrRender(_ctx, _push, _parent) {
-          _push(\`<!----><div></div><!---->\`)
+          _push(\`<div></div>\`)
         }"
       `)
     })
index a5b9ebd4c350a92d2f611e89f87e0acc9bf5a03b..eb301ab9bbed6be4288ce772685f252230ea93c6 100644 (file)
@@ -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(\`<div></div>\`)
         })
-        _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(\`<div>foo<span>bar</span></div>\`)
         })
-        _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(\`<div><!---->\`)
+          _push(\`<div>\`)
           _ssrRenderList(row, (j) => {
             _push(\`<div>\${
               _ssrInterpolate(i)
@@ -51,9 +46,8 @@ describe('ssr: v-for', () => {
               _ssrInterpolate(j)
             }</div>\`)
           })
-          _push(\`<!----></div>\`)
+          _push(\`</div>\`)
         })
-        _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(\`<span>\${_ssrInterpolate(i)}</span>\`)
         })
-        _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(\`<!----><span>\${
+          _push(\`<span>\${
             _ssrInterpolate(i)
           }</span><span>\${
             _ssrInterpolate(i + 1)
-          }</span><!---->\`)
+          }</span>\`)
         })
-        _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(\`<div>\${_ssrInterpolate(foo + _ctx.bar + index)}</div>\`)
         })
-        _push(\`<!---->\`)
       }"
     `)
   })
index 4f9157456e8cb85335586fc9c65011b6a401c362..8ea086797fe028bc817a697bef1714944bb6703c 100644 (file)
@@ -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(\`<!----><div>hi</div><div>ho</div><!---->\`)
+          _push(\`<div>hi</div><div>ho</div>\`)
         } 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(\`<div></div>\`)
           })
-          _push(\`<!---->\`)
         } else {
           _push(\`<!---->\`)
         }
@@ -147,7 +145,7 @@ describe('ssr: v-if', () => {
       "
       return function ssrRender(_ctx, _push, _parent) {
         if (_ctx.foo) {
-          _push(\`<!----><div>hi</div><div>ho</div><!---->\`)
+          _push(\`<div>hi</div><div>ho</div>\`)
         } else {
           _push(\`<div></div>\`)
         }
index 5afe4b55e96d435fdccacb74fcc5a5dc6c310c19..b9ef0c1669109043e130a93ba6d1e4deadfd3617 100644 (file)
@@ -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)
 }
index e81e13a4881afb2ab0e3a572dfccba34be1fecd7..5a3ad978ffad8b366891442b4c875d3bb893700e 100644 (file)
@@ -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
index 1b6034ba8aca8aa5205c87c291c93064716c495d..1921b8f0020c3fd33f87a27d674ab836f4f992e0 100644 (file)
@@ -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(`<!---->`)
 }
index aad7ad14d98b00579251a9d15ef452faf40ce575..d1c71e1d51fcdde9216cd69c31c03c0e88fd4f5b 100644 (file)
@@ -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)
-}
index a7d5ca6b93bff577a41421ad6db92ba5f003536e..36f3617401a2abcf29628bfd592012df1d97d17f 100644 (file)
@@ -281,7 +281,7 @@ describe('api: options', () => {
       }
     } as any
 
-    expect(renderToString(h(Root))).toBe(`<!---->1112<!---->`)
+    expect(renderToString(h(Root))).toBe(`1112`)
   })
 
   test('lifecycle', async () => {
index b71d5d6fba37bf86eec915524edc11b1cb335b1d..52e1676a5e71eab8fc4efe596f569381550e97b2 100644 (file)
@@ -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()
index 6a115e39c250510312e8ce8a288f17be84811d6e..1191440684c7b1f3bfd6072f7418fb24201489a1 100644 (file)
@@ -451,14 +451,14 @@ describe('Suspense', () => {
     await deps[0]
     await nextTick()
     expect(serializeInner(root)).toBe(
-      `<!----><div>async outer</div><div>fallback inner</div><!---->`
+      `<div>async outer</div><div>fallback inner</div>`
     )
     expect(calls).toEqual([`outer mounted`])
 
     await Promise.all(deps)
     await nextTick()
     expect(serializeInner(root)).toBe(
-      `<!----><div>async outer</div><div>async inner</div><!---->`
+      `<div>async outer</div><div>async inner</div>`
     )
     expect(calls).toEqual([`outer mounted`, `inner mounted`])
   })
@@ -522,7 +522,7 @@ describe('Suspense', () => {
     await Promise.all(deps)
     await nextTick()
     expect(serializeInner(root)).toBe(
-      `<!----><div>async outer</div><div>async inner</div><!---->`
+      `<div>async outer</div><div>async inner</div>`
     )
     expect(calls).toEqual([`inner mounted`, `outer mounted`])
   })
@@ -663,7 +663,7 @@ describe('Suspense', () => {
     await deps[3]
     await nextTick()
     expect(serializeInner(root)).toBe(
-      `<!----><div>nested fallback</div><div>root async</div><!---->`
+      `<div>nested fallback</div><div>root async</div>`
     )
     expect(calls).toEqual([0, 1, 3])
 
@@ -674,7 +674,7 @@ describe('Suspense', () => {
     await Promise.all(deps)
     await nextTick()
     expect(serializeInner(root)).toBe(
-      `<!----><div>nested changed</div><div>root async</div><!---->`
+      `<div>nested changed</div><div>root async</div>`
     )
     expect(calls).toEqual([0, 1, 3, 2])
 
@@ -682,7 +682,7 @@ describe('Suspense', () => {
     msg.value = 'nested changed again'
     await nextTick()
     expect(serializeInner(root)).toBe(
-      `<!----><div>nested changed again</div><div>root async</div><!---->`
+      `<div>nested changed again</div><div>root async</div>`
     )
   })
 
@@ -717,7 +717,7 @@ describe('Suspense', () => {
 
     await deps[0]
     await nextTick()
-    expect(serializeInner(root)).toBe(`<!----><div>Child A</div><!----><!---->`)
+    expect(serializeInner(root)).toBe(`<div>Child A</div><!---->`)
 
     toggle.value = true
     await nextTick()
@@ -725,9 +725,7 @@ describe('Suspense', () => {
 
     await deps[1]
     await nextTick()
-    expect(serializeInner(root)).toBe(
-      `<!----><div>Child A</div><div>Child B</div><!---->`
-    )
+    expect(serializeInner(root)).toBe(`<div>Child A</div><div>Child B</div>`)
   })
 
   test.todo('portal inside suspense')
index 77d48c3cc3a1e3d56dfe8f6d251d99e3858c3021..4a47a585826e0ec2b697a7d4cd031c38a243613a 100644 (file)
@@ -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`] = `"<!----><!--[object Object]--><div>root</div><!---->"`;
+exports[`renderer: portal should update target 1`] = `"<!--portal--><div>root</div>"`;
 
 exports[`renderer: portal should update target 2`] = `"<div>teleported</div>"`;
 
 exports[`renderer: portal should update target 3`] = `""`;
 
-exports[`renderer: portal should update target 4`] = `"<!----><!--[object Object]--><div>root</div><!---->"`;
+exports[`renderer: portal should update target 4`] = `"<!--portal--><div>root</div>"`;
 
 exports[`renderer: portal should update target 5`] = `""`;
 
 exports[`renderer: portal should update target 6`] = `"<div>teleported</div>"`;
 
-exports[`renderer: portal should work 1`] = `"<!----><!--[object Object]--><div>root</div><!---->"`;
+exports[`renderer: portal should work 1`] = `"<!--portal--><div>root</div>"`;
 
 exports[`renderer: portal should work 2`] = `"<div>teleported</div>"`;
index 4da8d0db4b9b4e09758248b958f5d07c2e4a717f..08b734fa3ca35f0ebdc181fdd87d79d1c9a6e050 100644 (file)
@@ -60,13 +60,13 @@ describe('hot module replacement', () => {
     createRecord(parentId, Parent)
 
     render(h(Parent), root)
-    expect(serializeInner(root)).toBe(`<div>0<!---->0<!----></div>`)
+    expect(serializeInner(root)).toBe(`<div>00</div>`)
 
     // 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(`<div>1<!---->1<!----></div>`)
+    expect(serializeInner(root)).toBe(`<div>11</div>`)
 
     // Update text while preserving state
     rerender(
@@ -75,7 +75,7 @@ describe('hot module replacement', () => {
         `<div @click="count++">{{ count }}!<Child>{{ count }}</Child></div>`
       )
     )
-    expect(serializeInner(root)).toBe(`<div>1!<!---->1<!----></div>`)
+    expect(serializeInner(root)).toBe(`<div>1!1</div>`)
 
     // Should force child update on slot content change
     rerender(
@@ -84,7 +84,7 @@ describe('hot module replacement', () => {
         `<div @click="count++">{{ count }}!<Child>{{ count }}!</Child></div>`
       )
     )
-    expect(serializeInner(root)).toBe(`<div>1!<!---->1!<!----></div>`)
+    expect(serializeInner(root)).toBe(`<div>1!1!</div>`)
 
     // Should force update element children despite block optimization
     rerender(
@@ -95,9 +95,7 @@ describe('hot module replacement', () => {
       </div>`
       )
     )
-    expect(serializeInner(root)).toBe(
-      `<div>1<span>1</span><!---->1!<!----></div>`
-    )
+    expect(serializeInner(root)).toBe(`<div>1<span>1</span>1!</div>`)
 
     // Should force update child slot elements
     rerender(
@@ -108,7 +106,7 @@ describe('hot module replacement', () => {
       </div>`
       )
     )
-    expect(serializeInner(root)).toBe(`<div><!----><span>1</span><!----></div>`)
+    expect(serializeInner(root)).toBe(`<div><span>1</span></div>`)
   })
 
   test('reload', async () => {
index fe34eee601084f602c7e7af67395d21127515fb3..136a0125610663ba81d05844a3565eeb369822df 100644 (file)
@@ -322,9 +322,7 @@ describe('attribute fallthrough', () => {
     render(h(Parent), root)
 
     expect(`Extraneous non-props attributes`).not.toHaveBeenWarned()
-    expect(root.innerHTML).toBe(
-      `<!----><div></div><div class="parent"></div><!---->`
-    )
+    expect(root.innerHTML).toBe(`<div></div><div class="parent"></div>`)
   })
 
   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(
-      `<!----><div></div><div class="parent"></div><!---->`
-    )
+    expect(root.innerHTML).toBe(`<div></div><div class="parent"></div>`)
   })
 })
index 091ef7a295cace06e0adf39343460d223d60f509..687bcbab2d268f8ae7fade6d632a939a8c99a19c 100644 (file)
@@ -25,10 +25,11 @@ describe('renderer: fragment', () => {
     const root = nodeOps.createElement('div')
     render(h(App), root)
 
-    expect(serializeInner(root)).toBe(`<!----><div>one</div>two<!---->`)
+    expect(serializeInner(root)).toBe(`<div>one</div>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(`<!----><div>one</div>two<!---->`)
+    expect(serializeInner(parent)).toBe(`<div>one</div>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(
-      `<!----><div>one</div><div>two</div><!---->`
-    )
+    expect(serializeInner(root)).toBe(`<div>one</div><div>two</div>`)
 
     resetOps()
     render(
       h(Fragment, [h('div', { key: 2 }, 'two'), h('div', { key: 1 }, 'one')]),
       root
     )
-    expect(serializeInner(root)).toBe(
-      `<!----><div>two</div><div>one</div><!---->`
-    )
+    expect(serializeInner(root)).toBe(`<div>two</div><div>one</div>`)
     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(
-      `<!----><div>one</div><div>two</div><!---->`
-    )
+    expect(serializeInner(root)).toBe(`<div>one</div><div>two</div>`)
 
     resetOps()
     render(h(Fragment, [h('div', 'two'), h('div', 'one')]), root)
-    expect(serializeInner(root)).toBe(
-      `<!----><div>two</div><div>one</div><!---->`
-    )
+    expect(serializeInner(root)).toBe(`<div>two</div><div>one</div>`)
     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(`<!----><div>one</div>two<!---->`)
+    expect(serializeInner(root)).toBe(`<div>one</div>two`)
 
     render(
       createVNode(
@@ -134,7 +128,7 @@ describe('renderer: fragment', () => {
       ),
       root
     )
-    expect(serializeInner(root)).toBe(`<!----><div>foo</div>barbaz<!---->`)
+    expect(serializeInner(root)).toBe(`<div>foo</div>barbaz`)
   })
 
   it('patch fragment children (compiler generated, keyed)', () => {
@@ -149,9 +143,7 @@ describe('renderer: fragment', () => {
       ),
       root
     )
-    expect(serializeInner(root)).toBe(
-      `<!----><div>one</div><div>two</div><!---->`
-    )
+    expect(serializeInner(root)).toBe(`<div>one</div><div>two</div>`)
 
     resetOps()
     render(
@@ -163,9 +155,7 @@ describe('renderer: fragment', () => {
       ),
       root
     )
-    expect(serializeInner(root)).toBe(
-      `<!----><div>two</div><div>one</div><!---->`
-    )
+    expect(serializeInner(root)).toBe(`<div>two</div><div>one</div>`)
     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(
-      `<div><div>outer</div><!----><div>one</div><div>two</div><!----></div>`
+      `<div><div>outer</div><div>one</div><div>two</div></div>`
     )
 
     resetOps()
@@ -203,7 +193,7 @@ describe('renderer: fragment', () => {
       root
     )
     expect(serializeInner(root)).toBe(
-      `<div><!----><div>two</div><div>one</div><!----><div>outer</div></div>`
+      `<div><div>two</div><div>one</div><div>outer</div></div>`
     )
     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(
-      `<!----><div>outer</div><!----><div>one</div><div>two</div><!----><!---->`
+      `<div>outer</div><div>one</div><div>two</div>`
     )
 
     resetOps()
@@ -249,16 +239,16 @@ describe('renderer: fragment', () => {
       root
     )
     expect(serializeInner(root)).toBe(
-      `<!----><!----><div>two</div><div>one</div><!----><div>outer</div><!---->`
+      `<div>two</div><div>one</div><div>outer</div>`
     )
     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
index 8861a198401abe0b79e612c8311f7053705ca638..ffe71ad36099f791db1520d316ded5047cce79f4 100644 (file)
@@ -24,7 +24,7 @@ export type RootHydrateFunction = (
 // passed in via arguments.
 export function createHydrationFunctions({
   mt: mountComponent,
-  o: { patchProp }
+  o: { patchProp, createText }
 }: RendererInternals<Node, Element>) {
   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?)
index a92708633ca9a60b56ebec29a5a9012a2b0a6364..3e0cef8c1ca06fbeab305ddc1382e5cff083622c 100644 (file)
@@ -126,7 +126,6 @@ export interface RendererInternals<HostNode = any, HostElement = any> {
   pbc: PatchBlockChildrenFn<HostNode, HostElement>
   n: NextFn<HostNode, HostElement>
   o: RendererOptions<HostNode, HostElement>
-  c: ProcessTextOrCommentFn<HostNode, HostElement>
 }
 
 // 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
   }
 
index c8bb79c8746ca32e4094149f47dbec8ae514a70b..730f7a1457295dfd1140a35e38066b5946c33624 100644 (file)
@@ -262,7 +262,7 @@ describe('ssr: renderToString', () => {
         )
       ).toBe(
         `<div>parent<div class="child">` +
-          `<!----><span>from slot</span><!---->` +
+          `<span>from slot</span>` +
           `</div></div>`
       )
 
@@ -277,7 +277,7 @@ describe('ssr: renderToString', () => {
             }
           })
         )
-      ).toBe(`<div>parent<div class="child"><!---->fallback<!----></div></div>`)
+      ).toBe(`<div>parent<div class="child">fallback</div></div>`)
     })
 
     test('nested components with vnode slots', async () => {
@@ -321,7 +321,7 @@ describe('ssr: renderToString', () => {
         )
       ).toBe(
         `<div>parent<div class="child">` +
-          `<!----><span>from slot</span><!---->` +
+          `<span>from slot</span>` +
           `</div></div>`
       )
     })
@@ -339,7 +339,7 @@ describe('ssr: renderToString', () => {
 
       expect(await renderToString(app)).toBe(
         `<div>parent<div class="child">` +
-          `<!----><span>from slot</span><!---->` +
+          `<span>from slot</span>` +
           `</div></div>`
       )
     })
@@ -461,9 +461,7 @@ describe('ssr: renderToString', () => {
             createCommentVNode('qux')
           ])
         )
-      ).toBe(
-        `<div>foo<span>bar</span><!----><span>baz</span><!----><!--qux--></div>`
-      )
+      ).toBe(`<div>foo<span>bar</span><span>baz</span><!--qux--></div>`)
     })
 
     test('void elements', async () => {
index d8826a03e1873b6b49ca3ce9b54f28b31be9bf4f..1aae61f2b1ae57d41e2f405a9a36af8e67559769 100644 (file)
@@ -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(`<!---->`)
 }
index 14c041c6561485837235efaa79fd6fc87734e80f..5b5ecc4d57a45c77146dd6ce0a2d25255281f4c0 100644 (file)
@@ -238,9 +238,7 @@ function renderVNode(
       push(children ? `<!--${children}-->` : `<!---->`)
       break
     case Fragment:
-      push(`<!---->`)
       renderVNodeChildren(push, children as VNodeArrayChildren, parentComponent)
-      push(`<!---->`)
       break
     default:
       if (shapeFlag & ShapeFlags.ELEMENT) {