Browse Source

wip: refactor

daiwei 1 year ago
parent
commit
aad75fd7c4

+ 5 - 3
packages/compiler-ssr/__tests__/ssrComponent.spec.ts

@@ -39,6 +39,7 @@ describe('ssr: components', () => {
 
         return function ssrRender(_ctx, _push, _parent, _attrs) {
           _ssrRenderVNode(_push, _createVNode(_resolveDynamicComponent("foo"), _mergeProps({ prop: "b" }, _attrs), null), _parent)
+          _push(\`<!--dynamic-component-->\`)
         }"
       `)
 
@@ -49,6 +50,7 @@ describe('ssr: components', () => {
 
         return function ssrRender(_ctx, _push, _parent, _attrs) {
           _ssrRenderVNode(_push, _createVNode(_resolveDynamicComponent(_ctx.foo), _mergeProps({ prop: "b" }, _attrs), null), _parent)
+          _push(\`<!--dynamic-component-->\`)
         }"
       `)
   })
@@ -245,7 +247,7 @@ describe('ssr: components', () => {
                     _push(\`<span\${_scopeId}></span>\`)
                   })
                   _push(\`<!--]--></div>\`)
-                  _push(\`<!--$-->\`)
+                  _push(\`<!--if-->\`)
                 } else {
                   _push(\`<!---->\`)
                 }
@@ -269,7 +271,7 @@ describe('ssr: components', () => {
                     _push(\`<span\${_scopeId}></span>\`)
                   })
                   _push(\`<!--]--></div>\`)
-                  _push(\`<!--$-->\`)
+                  _push(\`<!--if-->\`)
                 } else {
                   _push(\`<!---->\`)
                 }
@@ -363,7 +365,7 @@ describe('ssr: components', () => {
                   _push(\`\`)
                   if (false) {
                     _push(\`<div\${_scopeId}></div>\`)
-                    _push(\`<!--$-->\`)
+                    _push(\`<!--if-->\`)
                   } else {
                     _push(\`<!---->\`)
                   }

+ 1 - 1
packages/compiler-ssr/__tests__/ssrFallthroughAttrs.spec.ts

@@ -29,7 +29,7 @@ describe('ssr: attrs fallthrough', () => {
         _push(\`<!--[-->\`)
         if (true) {
           _push(\`<div></div>\`)
-          _push(\`<!--$-->\`)
+          _push(\`<!--if-->\`)
         } else {
           _push(\`<!---->\`)
         }

+ 1 - 1
packages/compiler-ssr/__tests__/ssrInjectCssVars.spec.ts

@@ -70,7 +70,7 @@ describe('ssr: inject <style vars>', () => {
         const _cssVars = { style: { color: _ctx.color }}
         if (_ctx.ok) {
           _push(\`<div\${_ssrRenderAttrs(_mergeProps(_attrs, _cssVars))}></div>\`)
-          _push(\`<!--$-->\`)
+          _push(\`<!--if-->\`)
         } else {
           _push(\`<!--[--><div\${
             _ssrRenderAttrs(_cssVars)

+ 1 - 1
packages/compiler-ssr/__tests__/ssrSlotOutlet.spec.ts

@@ -153,7 +153,7 @@ describe('ssr: <slot>', () => {
       return function ssrRender(_ctx, _push, _parent, _attrs) {
         if (true) {
           _ssrRenderSlotInner(_ctx.$slots, "default", {}, null, _push, _parent, null, true)
-          _push(\`<!--$-->\`)
+          _push(\`<!--if-->\`)
         } else {
           _push(\`<!---->\`)
         }

+ 2 - 2
packages/compiler-ssr/__tests__/ssrTransitionGroup.spec.ts

@@ -54,7 +54,7 @@ describe('transition-group', () => {
         })
         if (false) {
           _push(\`<div></div>\`)
-          _push(\`<!--$-->\`)
+          _push(\`<!--if-->\`)
         }
         _push(\`</ul>\`)
       }"
@@ -124,7 +124,7 @@ describe('transition-group', () => {
         })
         if (_ctx.ok) {
           _push(\`<div>ok</div>\`)
-          _push(\`<!--$-->\`)
+          _push(\`<!--if-->\`)
         }
         _push(\`<!--]-->\`)
       }"

+ 12 - 12
packages/compiler-ssr/__tests__/ssrVIf.spec.ts

@@ -8,7 +8,7 @@ describe('ssr: v-if', () => {
       return function ssrRender(_ctx, _push, _parent, _attrs) {
         if (_ctx.foo) {
           _push(\`<div\${_ssrRenderAttrs(_attrs)}></div>\`)
-          _push(\`<!--$-->\`)
+          _push(\`<!--if-->\`)
         } else {
           _push(\`<!---->\`)
         }
@@ -24,7 +24,7 @@ describe('ssr: v-if', () => {
         return function ssrRender(_ctx, _push, _parent, _attrs) {
           if (_ctx.foo) {
             _push(\`<div\${_ssrRenderAttrs(_attrs)}>hello<span>ok</span></div>\`)
-            _push(\`<!--$-->\`)
+            _push(\`<!--if-->\`)
           } else {
             _push(\`<!---->\`)
           }
@@ -40,7 +40,7 @@ describe('ssr: v-if', () => {
         return function ssrRender(_ctx, _push, _parent, _attrs) {
           if (_ctx.foo) {
             _push(\`<div\${_ssrRenderAttrs(_attrs)}></div>\`)
-            _push(\`<!--$-->\`)
+            _push(\`<!--if-->\`)
           } else {
             _push(\`<span\${_ssrRenderAttrs(_attrs)}></span>\`)
           }
@@ -56,10 +56,10 @@ describe('ssr: v-if', () => {
         return function ssrRender(_ctx, _push, _parent, _attrs) {
           if (_ctx.foo) {
             _push(\`<div\${_ssrRenderAttrs(_attrs)}></div>\`)
-            _push(\`<!--$-->\`)
+            _push(\`<!--if-->\`)
           } else if (_ctx.bar) {
             _push(\`<span\${_ssrRenderAttrs(_attrs)}></span>\`)
-            _push(\`<!--$-->\`)
+            _push(\`<!--if-->\`)
           } else {
             _push(\`<!---->\`)
           }
@@ -75,10 +75,10 @@ describe('ssr: v-if', () => {
         return function ssrRender(_ctx, _push, _parent, _attrs) {
           if (_ctx.foo) {
             _push(\`<div\${_ssrRenderAttrs(_attrs)}></div>\`)
-            _push(\`<!--$-->\`)
+            _push(\`<!--if-->\`)
           } else if (_ctx.bar) {
             _push(\`<span\${_ssrRenderAttrs(_attrs)}></span>\`)
-            _push(\`<!--$-->\`)
+            _push(\`<!--if-->\`)
           } else {
             _push(\`<p\${_ssrRenderAttrs(_attrs)}></p>\`)
           }
@@ -93,7 +93,7 @@ describe('ssr: v-if', () => {
         return function ssrRender(_ctx, _push, _parent, _attrs) {
           if (_ctx.foo) {
             _push(\`<!--[-->hello<!--]-->\`)
-            _push(\`<!--$-->\`)
+            _push(\`<!--if-->\`)
           } else {
             _push(\`<!---->\`)
           }
@@ -110,7 +110,7 @@ describe('ssr: v-if', () => {
         return function ssrRender(_ctx, _push, _parent, _attrs) {
           if (_ctx.foo) {
             _push(\`<div\${_ssrRenderAttrs(_attrs)}>hi</div>\`)
-            _push(\`<!--$-->\`)
+            _push(\`<!--if-->\`)
           } else {
             _push(\`<!---->\`)
           }
@@ -127,7 +127,7 @@ describe('ssr: v-if', () => {
       return function ssrRender(_ctx, _push, _parent, _attrs) {
         if (_ctx.foo) {
           _push(\`<!--[--><div>hi</div><div>ho</div><!--]-->\`)
-          _push(\`<!--$-->\`)
+          _push(\`<!--if-->\`)
         } else {
           _push(\`<!---->\`)
         }
@@ -148,7 +148,7 @@ describe('ssr: v-if', () => {
             _push(\`<div></div>\`)
           })
           _push(\`<!--]-->\`)
-          _push(\`<!--$-->\`)
+          _push(\`<!--if-->\`)
         } else {
           _push(\`<!---->\`)
         }
@@ -167,7 +167,7 @@ describe('ssr: v-if', () => {
       return function ssrRender(_ctx, _push, _parent, _attrs) {
         if (_ctx.foo) {
           _push(\`<!--[--><div>hi</div><div>ho</div><!--]-->\`)
-          _push(\`<!--$-->\`)
+          _push(\`<!--if-->\`)
         } else {
           _push(\`<div\${_ssrRenderAttrs(_attrs)}></div>\`)
         }

+ 1 - 1
packages/compiler-ssr/__tests__/ssrVModel.spec.ts

@@ -91,7 +91,7 @@ describe('ssr: v-model', () => {
               ? _ssrLooseContain(_ctx.model, _ctx.i)
               : _ssrLooseEqual(_ctx.model, _ctx.i))) ? " selected" : ""
           }></option>\`)
-          _push(\`<!--$-->\`)
+          _push(\`<!--if-->\`)
         } else {
           _push(\`<!---->\`)
         }

+ 8 - 3
packages/compiler-ssr/src/ssrCodegenTransform.ts

@@ -21,7 +21,12 @@ import {
   isText,
   processExpression,
 } from '@vue/compiler-dom'
-import { escapeHtml, isString } from '@vue/shared'
+import {
+  DYNAMIC_END_ANCHOR_LABEL,
+  DYNAMIC_START_ANCHOR_LABEL,
+  escapeHtml,
+  isString,
+} from '@vue/shared'
 import { SSR_INTERPOLATE, ssrHelpers } from './runtimeHelpers'
 import { ssrProcessIf } from './transforms/ssrVIf'
 import { ssrProcessFor } from './transforms/ssrVFor'
@@ -161,7 +166,7 @@ export function processChildren(
   asDynamic = false,
 ): void {
   if (asDynamic) {
-    context.pushStringPart(`<!--[[-->`)
+    context.pushStringPart(`<!--${DYNAMIC_START_ANCHOR_LABEL}-->`)
   }
   if (asFragment) {
     context.pushStringPart(`<!--[-->`)
@@ -259,7 +264,7 @@ export function processChildren(
     context.pushStringPart(`<!--]-->`)
   }
   if (asDynamic) {
-    context.pushStringPart(`<!--]]-->`)
+    context.pushStringPart(`<!--${DYNAMIC_END_ANCHOR_LABEL}-->`)
   }
 }
 

+ 10 - 1
packages/compiler-ssr/src/transforms/ssrTransformComponent.ts

@@ -55,7 +55,14 @@ import {
   ssrProcessTransitionGroup,
   ssrTransformTransitionGroup,
 } from './ssrTransformTransitionGroup'
-import { extend, isArray, isObject, isPlainObject, isSymbol } from '@vue/shared'
+import {
+  DYNAMIC_COMPONENT_ANCHOR_LABEL,
+  extend,
+  isArray,
+  isObject,
+  isPlainObject,
+  isSymbol,
+} from '@vue/shared'
 import { buildSSRProps } from './ssrTransformElement'
 import {
   ssrProcessTransition,
@@ -264,6 +271,8 @@ export function ssrProcessComponent(
       // dynamic component (`resolveDynamicComponent` call)
       // the codegen node is a `renderVNode` call
       context.pushStatement(node.ssrCodegenNode)
+      // anchor for dynamic component for vapor hydration
+      context.pushStringPart(`<!--${DYNAMIC_COMPONENT_ANCHOR_LABEL}-->`)
     }
   }
 }

+ 5 - 1
packages/compiler-ssr/src/transforms/ssrVIf.ts

@@ -14,6 +14,7 @@ import {
   type SSRTransformContext,
   processChildrenAsStatement,
 } from '../ssrCodegenTransform'
+import { IF_ANCHOR_LABEL } from '@vue/shared'
 
 // Plugin for the first transform pass, which simply constructs the AST node
 export const ssrTransformIf: NodeTransform = createStructuralDirectiveTransform(
@@ -80,7 +81,10 @@ function processIfBranch(
     needFragmentWrapper,
   )
   if (branch.condition) {
-    statement.body.push(createCallExpression(`_push`, ['`<!--$-->`']))
+    // v-if/v-else-if anchor for vapor hydration
+    statement.body.push(
+      createCallExpression(`_push`, [`\`<!--${IF_ANCHOR_LABEL}-->\``]),
+    )
   }
   return statement
 }

+ 6 - 6
packages/runtime-core/__tests__/hydration.spec.ts

@@ -598,14 +598,14 @@ describe('SSR hydration', () => {
     const ctx: SSRContext = {}
     container.innerHTML = await renderToString(h(App), ctx)
     expect(container.innerHTML).toBe(
-      '<div><!--teleport start--><!--teleport end--><!--$--></div>',
+      '<div><!--teleport start--><!--teleport end--><!--if--></div>',
     )
     teleportContainer.innerHTML = ctx.teleports!['#target']
 
     // hydrate
     createSSRApp(App).mount(container)
     expect(container.innerHTML).toBe(
-      '<div><!--teleport start--><!--teleport end--><!--$--></div>',
+      '<div><!--teleport start--><!--teleport end--><!--if--></div>',
     )
     expect(teleportContainer.innerHTML).toBe(
       '<!--teleport start anchor--><span>Teleported Comp1</span><!--teleport anchor-->',
@@ -614,7 +614,7 @@ describe('SSR hydration', () => {
 
     toggle.value = false
     await nextTick()
-    expect(container.innerHTML).toBe('<div><div>Comp2</div><!--$--></div>')
+    expect(container.innerHTML).toBe('<div><div>Comp2</div><!--if--></div>')
     expect(teleportContainer.innerHTML).toBe('')
   })
 
@@ -657,21 +657,21 @@ describe('SSR hydration', () => {
     // server render
     container.innerHTML = await renderToString(h(App))
     expect(container.innerHTML).toBe(
-      '<div><!--teleport start--><!--teleport end--><!--$--></div>',
+      '<div><!--teleport start--><!--teleport end--><!--if--></div>',
     )
     expect(teleportContainer.innerHTML).toBe('')
 
     // hydrate
     createSSRApp(App).mount(container)
     expect(container.innerHTML).toBe(
-      '<div><!--teleport start--><!--teleport end--><!--$--></div>',
+      '<div><!--teleport start--><!--teleport end--><!--if--></div>',
     )
     expect(teleportContainer.innerHTML).toBe('<span>Teleported Comp1</span>')
     expect(`Hydration children mismatch`).toHaveBeenWarned()
 
     toggle.value = false
     await nextTick()
-    expect(container.innerHTML).toBe('<div><div>Comp2</div><!--$--></div>')
+    expect(container.innerHTML).toBe('<div><div>Comp2</div><!--if--></div>')
     expect(teleportContainer.innerHTML).toBe('')
   })
 

+ 4 - 10
packages/runtime-core/src/hydration.ts

@@ -25,6 +25,8 @@ import {
   getEscapedCssVarName,
   includeBooleanAttr,
   isBooleanAttr,
+  isDynamicAnchor,
+  isDynamicFragmentEndAnchor,
   isKnownHtmlAttr,
   isKnownSvgAttr,
   isOn,
@@ -84,14 +86,6 @@ const getContainerType = (
   return undefined
 }
 
-export function isDynamicAnchor(node: Node): node is Comment {
-  return isComment(node) && (node.data === '[[' || node.data === ']]')
-}
-
-export function isDynamicFragmentEndAnchor(node: Node): node is Comment {
-  return isComment(node) && node.data === '$'
-}
-
 export const isComment = (node: Node): node is Comment =>
   node.nodeType === DOMNodeTypes.COMMENT
 
@@ -130,8 +124,8 @@ export function createHydrationFunctions(
   function nextSibling(node: Node) {
     let n = next(node)
     // skip if:
-    // - dynamic anchors (`<!--[-->`, `<!--]-->`)
-    // - dynamic fragment end anchors (`<!--$-->`)
+    // - dynamic anchors (`<!--[[-->`, `<!--][-->`)
+    // - dynamic fragment end anchors (e.g. `<!--if-->`, `<!--for-->`)
     if (n && (isDynamicAnchor(n) || isDynamicFragmentEndAnchor(n))) {
       n = next(n)
     }

+ 0 - 4
packages/runtime-core/src/index.ts

@@ -557,7 +557,3 @@ export { startMeasure, endMeasure } from './profiling'
  * @internal
  */
 export { initFeatureFlags } from './featureFlags'
-/**
- * @internal
- */
-export { isDynamicAnchor, isDynamicFragmentEndAnchor } from './hydration'

File diff suppressed because it is too large
+ 566 - 562
packages/runtime-vapor/__tests__/hydration.spec.ts


+ 4 - 9
packages/runtime-vapor/src/apiCreateDynamicComponent.ts

@@ -9,7 +9,8 @@ import {
   insertionParent,
   resetInsertionState,
 } from './insertionState'
-import { isHydrating, locateHydrationNode } from './dom/hydration'
+import { isHydrating } from './dom/hydration'
+import { DYNAMIC_COMPONENT_ANCHOR_LABEL } from '@vue/shared'
 
 export function createDynamicComponent(
   getter: () => any,
@@ -19,15 +20,9 @@ export function createDynamicComponent(
 ): VaporFragment {
   const _insertionParent = insertionParent
   const _insertionAnchor = insertionAnchor
-  if (isHydrating) {
-    locateHydrationNode(true)
-  } else {
-    resetInsertionState()
-  }
+  if (!isHydrating) resetInsertionState()
 
-  const frag = __DEV__
-    ? new DynamicFragment('dynamic-component')
-    : new DynamicFragment()
+  const frag = new DynamicFragment(DYNAMIC_COMPONENT_ANCHOR_LABEL)
   renderEffect(() => {
     const value = getter()
     frag.update(

+ 9 - 6
packages/runtime-vapor/src/apiCreateIf.ts

@@ -1,6 +1,11 @@
+import { IF_ANCHOR_LABEL } from '@vue/shared'
 import { type Block, type BlockFn, DynamicFragment, insert } from './block'
-import { isHydrating, locateHydrationNode } from './dom/hydration'
-import { insertionAnchor, insertionParent } from './insertionState'
+import { isHydrating } from './dom/hydration'
+import {
+  insertionAnchor,
+  insertionParent,
+  resetInsertionState,
+} from './insertionState'
 import { renderEffect } from './renderEffect'
 
 export function createIf(
@@ -11,15 +16,13 @@ export function createIf(
 ): Block {
   const _insertionParent = insertionParent
   const _insertionAnchor = insertionAnchor
-  if (isHydrating) {
-    locateHydrationNode(true)
-  }
+  if (!isHydrating) resetInsertionState()
 
   let frag: Block
   if (once) {
     frag = condition() ? b1() : b2 ? b2() : []
   } else {
-    frag = __DEV__ ? new DynamicFragment('if') : new DynamicFragment()
+    frag = new DynamicFragment(IF_ANCHOR_LABEL)
     renderEffect(() => (frag as DynamicFragment).update(condition() ? b1 : b2))
   }
 

+ 13 - 8
packages/runtime-vapor/src/block.ts

@@ -1,4 +1,4 @@
-import { isArray } from '@vue/shared'
+import { isArray, isDynamicFragmentEndAnchor } from '@vue/shared'
 import {
   type VaporComponentInstance,
   isVaporComponent,
@@ -7,8 +7,13 @@ import {
 } from './component'
 import { createComment, createTextNode, nextSiblingAnchor } from './dom/node'
 import { EffectScope, pauseTracking, resetTracking } from '@vue/reactivity'
-import { currentHydrationNode, isComment, isHydrating } from './dom/hydration'
-import { isDynamicFragmentEndAnchor, warn } from '@vue/runtime-dom'
+import {
+  currentHydrationNode,
+  isComment,
+  isHydrating,
+  locateHydrationNode,
+} from './dom/hydration'
+import { warn } from '@vue/runtime-dom'
 
 export type Block =
   | Node
@@ -39,7 +44,8 @@ export class DynamicFragment extends VaporFragment {
   constructor(anchorLabel?: string) {
     super([])
     if (isHydrating) {
-      this.hydrate(anchorLabel)
+      locateHydrationNode(true)
+      this.hydrate(anchorLabel!)
     } else {
       this.anchor =
         __DEV__ && anchorLabel ? createComment(anchorLabel) : createTextNode()
@@ -81,15 +87,15 @@ export class DynamicFragment extends VaporFragment {
     resetTracking()
   }
 
-  hydrate(label?: string): void {
+  hydrate(label: string): void {
     // for v-if="false" the hydrationNode will be a empty comment node
     // use it as anchor.
     // otherwise, use the next sibling comment node as anchor
     if (isComment(currentHydrationNode!, '')) {
       this.anchor = currentHydrationNode
     } else {
-      // find next sibling `<!--$-->` as anchor
-      const anchor = nextSiblingAnchor(currentHydrationNode!, '$')!
+      // find next sibling dynamic fragment end anchor
+      const anchor = nextSiblingAnchor(currentHydrationNode!, label)!
       if (anchor && isDynamicFragmentEndAnchor(anchor)) {
         this.anchor = anchor
       } else if (__DEV__) {
@@ -97,7 +103,6 @@ export class DynamicFragment extends VaporFragment {
         warn(`DynamicFragment anchor not found...`)
       }
     }
-    if (__DEV__ && label && this.anchor) (this.anchor as Comment).data = label
   }
 }
 

+ 2 - 1
packages/runtime-vapor/src/dom/hydration.ts

@@ -1,4 +1,4 @@
-import { isDynamicFragmentEndAnchor, warn } from '@vue/runtime-dom'
+import { warn } from '@vue/runtime-dom'
 import {
   insertionAnchor,
   insertionParent,
@@ -12,6 +12,7 @@ import {
   next,
   prev,
 } from './node'
+import { isDynamicFragmentEndAnchor } from '@vue/shared'
 
 export let isHydrating = false
 export let currentHydrationNode: Node | null = null

+ 21 - 17
packages/runtime-vapor/src/dom/node.ts

@@ -1,10 +1,15 @@
-import { isDynamicAnchor } from '@vue/runtime-dom'
 import {
   isComment,
   isEmptyText,
   locateEndAnchor,
   locateStartAnchor,
 } from './hydration'
+import {
+  DYNAMIC_END_ANCHOR_LABEL,
+  DYNAMIC_START_ANCHOR_LABEL,
+  isDynamicAnchor,
+  isDynamicFragmentEndAnchor,
+} from '@vue/shared'
 
 /*! #__NO_SIDE_EFFECTS__ */
 export function createTextNode(value = ''): Text {
@@ -102,8 +107,12 @@ export function disableHydrationNodeLookup(): void {
 /*! #__NO_SIDE_EFFECTS__ */
 export function prev(node: Node): Node | null {
   // process dynamic node (<!--[[-->...<!--]]-->) as a single one
-  if (isComment(node, ']]')) {
-    node = locateStartAnchor(node, '[[', ']]')!
+  if (isComment(node, DYNAMIC_END_ANCHOR_LABEL)) {
+    node = locateStartAnchor(
+      node,
+      DYNAMIC_START_ANCHOR_LABEL,
+      DYNAMIC_END_ANCHOR_LABEL,
+    )!
   }
 
   // process fragment node (<!--[-->...<!--]-->) as a single one
@@ -122,21 +131,12 @@ function isNonHydrationNode(node: Node) {
   return (
     // empty text nodes, no need to hydrate
     isEmptyText(node) ||
-    // dynamic anchors (<!--[[-->, <!--]]-->)
+    // dynamic node anchors (<!--[[-->, <!--]]-->)
     isDynamicAnchor(node) ||
     // fragment end anchor (`<!--]-->`)
     isComment(node, ']') ||
-    // dynamic fragment anchors
-    (__DEV__
-      ? // v-if anchor (`<!--if-->`)
-        isComment(node, 'if') ||
-        // v-for anchor (`<!--for-->`)
-        isComment(node, 'for') ||
-        // v-slot anchor (`<!--slot-->`)
-        isComment(node, 'slot') ||
-        // dynamic-component anchor (`<!--dynamic-component-->`)
-        isComment(node, 'dynamic-component')
-      : isComment(node, '$'))
+    // dynamic fragment end anchors
+    isDynamicFragmentEndAnchor(node)
   )
 }
 
@@ -157,8 +157,12 @@ export function nextSiblingAnchor(
 
 function handleWrappedNode(node: Node): Node {
   // process dynamic node (<!--[[-->...<!--]]-->) as a single one
-  if (isComment(node, '[[')) {
-    return locateEndAnchor(node, '[[', ']]')!
+  if (isComment(node, DYNAMIC_START_ANCHOR_LABEL)) {
+    return locateEndAnchor(
+      node,
+      DYNAMIC_START_ANCHOR_LABEL,
+      DYNAMIC_END_ANCHOR_LABEL,
+    )!
   }
 
   // process fragment (<!--[-->...<!--]-->) as a single one

+ 1 - 1
packages/server-renderer/__tests__/ssrAttrFallthrough.spec.ts

@@ -25,7 +25,7 @@ describe('ssr: attr fallthrough', () => {
       template: `<child :ok="ok" class="bar"/>`,
     }
     expect(await renderToString(createApp(Parent, { ok: true }))).toBe(
-      `<div class="foo bar"></div><!--$-->`,
+      `<div class="foo bar"></div><!--if-->`,
     )
     expect(await renderToString(createApp(Parent, { ok: false }))).toBe(
       `<span class="bar"></span>`,

+ 9 - 5
packages/server-renderer/__tests__/ssrDynamicComponent.spec.ts

@@ -14,7 +14,9 @@ describe('ssr: dynamic component', () => {
           template: `<component :is="'one'"><span>slot</span></component>`,
         }),
       ),
-    ).toBe(`<div><!--[--><span>slot</span><!--]--></div>`)
+    ).toBe(
+      `<div><!--[--><span>slot</span><!--]--></div><!--dynamic-component-->`,
+    )
   })
 
   test('resolved to component with v-show', async () => {
@@ -30,7 +32,7 @@ describe('ssr: dynamic component', () => {
         }),
       ),
     ).toBe(
-      `<div><!--[--><div style=\"display:none;\"><!--[-->hi<!--]--></div><!--]--></div>`,
+      `<div><!--[--><div style="display:none;"><!--[-->hi<!--]--></div><!--dynamic-component--><!--]--></div><!--dynamic-component-->`,
     )
   })
 
@@ -41,7 +43,7 @@ describe('ssr: dynamic component', () => {
           template: `<component :is="'p'"><span>slot</span></component>`,
         }),
       ),
-    ).toBe(`<p><span>slot</span></p>`)
+    ).toBe(`<p><span>slot</span></p><!--dynamic-component-->`)
   })
 
   test('resolve to component vnode', async () => {
@@ -60,7 +62,9 @@ describe('ssr: dynamic component', () => {
           template: `<component :is="vnode"><span>slot</span></component>`,
         }),
       ),
-    ).toBe(`<div>test<!--[--><span>slot</span><!--]--></div>`)
+    ).toBe(
+      `<div>test<!--[--><span>slot</span><!--]--></div><!--dynamic-component-->`,
+    )
   })
 
   test('resolve to element vnode', async () => {
@@ -75,6 +79,6 @@ describe('ssr: dynamic component', () => {
           template: `<component :is="vnode"><span>slot</span></component>`,
         }),
       ),
-    ).toBe(`<div id="test"><span>slot</span></div>`)
+    ).toBe(`<div id="test"><span>slot</span></div><!--dynamic-component-->`)
   })
 })

+ 8 - 6
packages/server-renderer/__tests__/ssrSlot.spec.ts

@@ -94,7 +94,7 @@ describe('ssr: slot', () => {
           template: `<one><template v-if="true">hello</template></one>`,
         }),
       ),
-    ).toBe(`<div><!--[--><!--[-->hello<!--]--><!--$--><!--]--></div>`)
+    ).toBe(`<div><!--[--><!--[-->hello<!--]--><!--if--><!--]--></div>`)
   })
 
   test('fragment slot (template v-if + multiple elements)', async () => {
@@ -106,7 +106,7 @@ describe('ssr: slot', () => {
         }),
       ),
     ).toBe(
-      `<div><!--[--><!--[--><div>one</div><div>two</div><!--]--><!--$--><!--]--></div>`,
+      `<div><!--[--><!--[--><div>one</div><div>two</div><!--]--><!--if--><!--]--></div>`,
     )
   })
 
@@ -135,7 +135,7 @@ describe('ssr: slot', () => {
           template: `<one><div v-if="true">foo</div></one>`,
         }),
       ),
-    ).toBe(`<div>foo</div><!--$-->`)
+    ).toBe(`<div>foo</div><!--if-->`)
   })
 
   // #9933
@@ -170,7 +170,9 @@ describe('ssr: slot', () => {
           template: `<ButtonComp><Wrap><div v-if="false">hello</div></Wrap></ButtonComp>`,
         }),
       ),
-    ).toBe(`<button><!--[--><div><!--[--><!--]--></div><!--]--></button>`)
+    ).toBe(
+      `<button><!--[--><div><!--[--><!--]--></div><!--]--></button><!--dynamic-component-->`,
+    )
 
     expect(
       await renderToString(
@@ -187,7 +189,7 @@ describe('ssr: slot', () => {
         }),
       ),
     ).toBe(
-      `<button><!--[--><div><!--[--><div>hello</div><!--]--></div><!--]--></button>`,
+      `<button><!--[--><div><!--[--><div>hello</div><!--]--></div><!--]--></button><!--dynamic-component-->`,
     )
 
     expect(
@@ -201,6 +203,6 @@ describe('ssr: slot', () => {
           template: `<ButtonComp><template v-if="false">hello</template></ButtonComp>`,
         }),
       ),
-    ).toBe(`<button><!--[--><!--]--></button>`)
+    ).toBe(`<button><!--[--><!--]--></button><!--dynamic-component-->`)
   })
 })

+ 0 - 1
packages/server-renderer/src/render.ts

@@ -264,7 +264,6 @@ export function renderVNode(
         renderElementVNode(push, vnode, parentComponent, slotScopeId)
       } else if (shapeFlag & ShapeFlags.COMPONENT) {
         push(renderComponentVNode(vnode, parentComponent, slotScopeId))
-        push(`<!--$-->`) // anchor for vapor hydration
       } else if (shapeFlag & ShapeFlags.TELEPORT) {
         renderTeleportVNode(push, vnode, parentComponent, slotScopeId)
       } else if (shapeFlag & ShapeFlags.SUSPENSE) {

+ 30 - 0
packages/shared/src/domAnchors.ts

@@ -0,0 +1,30 @@
+export const DYNAMIC_START_ANCHOR_LABEL = '[['
+export const DYNAMIC_END_ANCHOR_LABEL = ']]'
+
+export const IF_ANCHOR_LABEL: string = __DEV__ ? 'if' : '$'
+export const DYNAMIC_COMPONENT_ANCHOR_LABEL: string = __DEV__
+  ? 'dynamic-component'
+  : '$2'
+export const FOR_ANCHOR_LABEL: string = __DEV__ ? 'for' : '$3'
+export const SLOT_ANCHOR_LABEL: string = __DEV__ ? 'slot' : '$4'
+
+export function isDynamicAnchor(node: Node): node is Comment {
+  if (node.nodeType !== 8) return false
+
+  const data = (node as Comment).data
+  return (
+    data === DYNAMIC_START_ANCHOR_LABEL || data === DYNAMIC_END_ANCHOR_LABEL
+  )
+}
+
+export function isDynamicFragmentEndAnchor(node: Node): node is Comment {
+  if (node.nodeType !== 8) return false
+
+  const data = (node as Comment).data
+  return (
+    data === IF_ANCHOR_LABEL ||
+    data === FOR_ANCHOR_LABEL ||
+    data === SLOT_ANCHOR_LABEL ||
+    data === DYNAMIC_COMPONENT_ANCHOR_LABEL
+  )
+}

+ 1 - 0
packages/shared/src/index.ts

@@ -13,3 +13,4 @@ export * from './looseEqual'
 export * from './toDisplayString'
 export * from './typeUtils'
 export * from './subSequence'
+export * from './domAnchors'

Some files were not shown because too many files changed in this diff