]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
wip: extract VaporFragment into a separate file
authordaiwei <daiwei521@126.com>
Wed, 26 Mar 2025 13:40:13 +0000 (21:40 +0800)
committerdaiwei <daiwei521@126.com>
Wed, 26 Mar 2025 14:14:37 +0000 (22:14 +0800)
 to resolve the circular dependency caused by TeleportFragment

12 files changed:
packages-private/vapor-e2e-test/__tests__/teleport.spec.ts
packages/runtime-vapor/__tests__/block.spec.ts
packages/runtime-vapor/src/apiCreateDynamicComponent.ts
packages/runtime-vapor/src/apiCreateFor.ts
packages/runtime-vapor/src/apiCreateIf.ts
packages/runtime-vapor/src/block.ts
packages/runtime-vapor/src/componentSlots.ts
packages/runtime-vapor/src/components/Teleport.ts
packages/runtime-vapor/src/directives/vShow.ts
packages/runtime-vapor/src/fragment.ts [new file with mode: 0644]
packages/runtime-vapor/src/index.ts
packages/runtime-vapor/src/vdomInterop.ts

index dc3efa13a4719c628c242bd99a4375d5502c9949..ce383dadf1c64a1f70eb576a8f56295621c80d86 100644 (file)
@@ -9,7 +9,7 @@ import { nextTick } from 'vue'
 import { ports } from '../utils'
 const { page, click, html } = setupPuppeteer()
 
-describe('vdom / vapor interop', () => {
+describe('vapor teleport', () => {
   let server: any
   const port = ports.teleport
   beforeAll(() => {
@@ -29,33 +29,34 @@ describe('vdom / vapor interop', () => {
     await page().waitForSelector('#app')
   })
 
-  describe('vapor teleport', () => {
-    test(
-      'render vdom component',
-      async () => {
-        const targetSelector = '.target'
-        const testSelector = '.interop-render-vdom-comp'
-        const containerSelector = `${testSelector} > div`
-        const btnSelector = `${testSelector} > button`
-
-        // teleport is disabled
-        expect(await html(containerSelector)).toBe('<h1>vdom comp</h1>')
-        expect(await html(targetSelector)).toBe('')
-
-        // enable teleport
-        await click(btnSelector)
-        await nextTick()
-
-        expect(await html(containerSelector)).toBe('')
-        expect(await html(targetSelector)).toBe('<h1>vdom comp</h1>')
-
-        // disable teleport
-        await click(btnSelector)
-        await nextTick()
-        expect(await html(containerSelector)).toBe('<h1>vdom comp</h1>')
-        expect(await html(targetSelector)).toBe('')
-      },
-      E2E_TIMEOUT,
-    )
-  })
+  test(
+    'render vdom component',
+    async () => {
+      const targetSelector = '.target'
+      const testSelector = '.interop-render-vdom-comp'
+      const containerSelector = `${testSelector} > div`
+      const btnSelector = `${testSelector} > button`
+
+      const tt = await html('#app')
+      console.log(tt)
+
+      // teleport is disabled
+      expect(await html(containerSelector)).toBe('<h1>vdom comp</h1>')
+      expect(await html(targetSelector)).toBe('')
+
+      // enable teleport
+      await click(btnSelector)
+      await nextTick()
+
+      expect(await html(containerSelector)).toBe('')
+      expect(await html(targetSelector)).toBe('<h1>vdom comp</h1>')
+
+      // disable teleport
+      await click(btnSelector)
+      await nextTick()
+      expect(await html(containerSelector)).toBe('<h1>vdom comp</h1>')
+      expect(await html(targetSelector)).toBe('')
+    },
+    E2E_TIMEOUT,
+  )
 })
index 9f76c7f0333bb8b0ba9b39ecc68bebbe31dd9f5a..f0144dee3df2f6cae77be369b9f140037a6d786c 100644 (file)
@@ -1,10 +1,5 @@
-import {
-  VaporFragment,
-  insert,
-  normalizeBlock,
-  prepend,
-  remove,
-} from '../src/block'
+import { insert, normalizeBlock, prepend, remove } from '../src/block'
+import { VaporFragment } from '../src/fragment'
 
 const node1 = document.createTextNode('node1')
 const node2 = document.createTextNode('node2')
index 2126611d7182e1cb548d4179e09dd536c8f3c920..abdc1a1cf24ed75f5a79c2bfb7af63774f4ceac5 100644 (file)
@@ -1,9 +1,9 @@
 import { resolveDynamicComponent } from '@vue/runtime-dom'
-import { DynamicFragment, type VaporFragment } from './block'
 import { createComponentWithFallback } from './component'
 import { renderEffect } from './renderEffect'
 import type { RawProps } from './componentProps'
 import type { RawSlots } from './componentSlots'
+import { DynamicFragment, type VaporFragment } from './fragment'
 
 export function createDynamicComponent(
   getter: () => any,
index 0cd8317532f4fb93790775321bf2015fbe2f09da..ca976aa8ccdf23e29f7ef42a7aa530ae240648a1 100644 (file)
@@ -11,12 +11,7 @@ import {
 } from '@vue/reactivity'
 import { getSequence, isArray, isObject, isString } from '@vue/shared'
 import { createComment, createTextNode } from './dom/node'
-import {
-  type Block,
-  VaporFragment,
-  insert,
-  remove as removeBlock,
-} from './block'
+import { type Block, insert, remove as removeBlock } from './block'
 import { warn } from '@vue/runtime-dom'
 import { currentInstance, isVaporComponent } from './component'
 import type { DynamicSlot } from './componentSlots'
@@ -24,6 +19,7 @@ import { renderEffect } from './renderEffect'
 import { VaporVForFlags } from '../../shared/src/vaporFlags'
 import { isHydrating, locateHydrationNode } from './dom/hydration'
 import { insertionAnchor, insertionParent } from './insertionState'
+import { VaporFragment } from './fragment'
 
 class ForBlock extends VaporFragment {
   scope: EffectScope | undefined
index 71bfa32d5d3fdbe07213ff6af3125da2c5f8dd25..e83b251d0698cfa6cdc0ef04fd4d5e2d0df5912c 100644 (file)
@@ -1,7 +1,8 @@
-import { type Block, type BlockFn, DynamicFragment, insert } from './block'
+import { type Block, type BlockFn, insert } from './block'
 import { isHydrating, locateHydrationNode } from './dom/hydration'
 import { insertionAnchor, insertionParent } from './insertionState'
 import { renderEffect } from './renderEffect'
+import { DynamicFragment } from './fragment'
 
 export function createIf(
   condition: () => any,
index 332595aac487f292518d1d362dd094e64b2ea5cd..f1791904ce85cc0a654761a0646f4a8d3ee2be29 100644 (file)
@@ -5,9 +5,12 @@ import {
   mountComponent,
   unmountComponent,
 } from './component'
-import { createComment, createTextNode } from './dom/node'
-import { EffectScope, pauseTracking, resetTracking } from '@vue/reactivity'
 import { isHydrating } from './dom/hydration'
+import {
+  type DynamicFragment,
+  type VaporFragment,
+  isFragment,
+} from './fragment'
 
 export type Block =
   | Node
@@ -18,72 +21,6 @@ export type Block =
 
 export type BlockFn = (...args: any[]) => Block
 
-export class VaporFragment {
-  nodes: Block
-  target?: ParentNode | null
-  targetAnchor?: Node | null
-  anchor?: Node
-  insert?: (parent: ParentNode, anchor: Node | null) => void
-  remove?: (parent?: ParentNode) => void
-  getNodes?: () => Block
-
-  constructor(nodes: Block) {
-    this.nodes = nodes
-  }
-}
-
-export class DynamicFragment extends VaporFragment {
-  anchor: Node
-  scope: EffectScope | undefined
-  current?: BlockFn
-  fallback?: BlockFn
-
-  constructor(anchorLabel?: string) {
-    super([])
-    this.anchor =
-      __DEV__ && anchorLabel ? createComment(anchorLabel) : createTextNode()
-  }
-
-  update(render?: BlockFn, key: any = render): void {
-    if (key === this.current) {
-      return
-    }
-    this.current = key
-
-    pauseTracking()
-    const parent = this.anchor.parentNode
-
-    // teardown previous branch
-    if (this.scope) {
-      this.scope.stop()
-      parent && remove(this.nodes, parent)
-    }
-
-    if (render) {
-      this.scope = new EffectScope()
-      this.nodes = this.scope.run(render) || []
-      if (parent) insert(this.nodes, parent, this.anchor)
-    } else {
-      this.scope = undefined
-      this.nodes = []
-    }
-
-    if (this.fallback && !isValidBlock(this.nodes)) {
-      parent && remove(this.nodes, parent)
-      this.nodes =
-        (this.scope || (this.scope = new EffectScope())).run(this.fallback) ||
-        []
-      parent && insert(this.nodes, parent, this.anchor)
-    }
-
-    resetTracking()
-  }
-}
-
-export function isFragment(val: NonNullable<unknown>): val is VaporFragment {
-  return val instanceof VaporFragment
-}
-
 export function isBlock(val: NonNullable<unknown>): val is Block {
   return (
     val instanceof Node ||
index 74296e09466359d9fddc37305b032b4e99741010..3d17e5c0a5b8b058bc166d18e6d5dc4e030df40b 100644 (file)
@@ -1,11 +1,12 @@
 import { EMPTY_OBJ, NO, hasOwn, isArray, isFunction } from '@vue/shared'
-import { type Block, type BlockFn, DynamicFragment, insert } from './block'
+import { type Block, type BlockFn, insert } from './block'
 import { rawPropsProxyHandlers } from './componentProps'
 import { currentInstance, isRef } from '@vue/runtime-dom'
 import type { LooseRawProps, VaporComponentInstance } from './component'
 import { renderEffect } from './renderEffect'
 import { insertionAnchor, insertionParent } from './insertionState'
 import { isHydrating, locateHydrationNode } from './dom/hydration'
+import { DynamicFragment } from './fragment'
 
 export type RawSlots = Record<string, VaporSlot> & {
   $?: DynamicSlotSource[]
index 040914ef984b80fcddd4664e67a91cbc0ccb7342..65fdc53e0ac16a70aee8ff3b1b044ffc13407efe 100644 (file)
@@ -7,13 +7,7 @@ import {
   resolveTarget,
   warn,
 } from '@vue/runtime-dom'
-import {
-  type Block,
-  type BlockFn,
-  VaporFragment,
-  insert,
-  remove,
-} from '../block'
+import { type Block, type BlockFn, insert, remove } from '../block'
 import { createComment, createTextNode, querySelector } from '../dom/node'
 import type {
   LooseRawProps,
@@ -24,6 +18,7 @@ import { rawPropsProxyHandlers } from '../componentProps'
 import { renderEffect } from '../renderEffect'
 import { extend, isArray } from '@vue/shared'
 import { EffectScope, pauseTracking, resetTracking } from '@vue/reactivity'
+import { VaporFragment } from '../fragment'
 
 export const teleportStack: TeleportFragment[] = __DEV__
   ? ([] as TeleportFragment[])
@@ -70,11 +65,11 @@ export const VaporTeleportImpl = {
     const scope = (frag.scope = new EffectScope())
     scope!.run(() => {
       renderEffect(() => {
-        teleportStack.push(frag)
+        __DEV__ && teleportStack.push(frag)
         frag.updateChildren(
           (frag.children = slots.default && (slots.default as BlockFn)()),
         )
-        teleportStack.pop()
+        __DEV__ && teleportStack.pop()
       })
 
       renderEffect(() => {
index ac4c066b71d6cbc78ed3d36fe1daf7bf0c2ba4b7..b0fc22c14c869923111322373e08692fe57b7c6d 100644 (file)
@@ -6,8 +6,9 @@ import {
 } from '@vue/runtime-dom'
 import { renderEffect } from '../renderEffect'
 import { isVaporComponent } from '../component'
-import { type Block, DynamicFragment } from '../block'
+import type { Block } from '../block'
 import { isArray } from '@vue/shared'
+import { DynamicFragment } from '../fragment'
 
 export function applyVShow(target: Block, source: () => any): void {
   if (isVaporComponent(target)) {
diff --git a/packages/runtime-vapor/src/fragment.ts b/packages/runtime-vapor/src/fragment.ts
new file mode 100644 (file)
index 0000000..3e4fcb2
--- /dev/null
@@ -0,0 +1,69 @@
+import { EffectScope, pauseTracking, resetTracking } from '@vue/reactivity'
+import { createComment, createTextNode } from './dom/node'
+import { type Block, type BlockFn, insert, isValidBlock, remove } from './block'
+
+export class VaporFragment {
+  nodes: Block
+  target?: ParentNode | null
+  targetAnchor?: Node | null
+  anchor?: Node
+  insert?: (parent: ParentNode, anchor: Node | null) => void
+  remove?: (parent?: ParentNode) => void
+  getNodes?: () => Block
+
+  constructor(nodes: Block) {
+    this.nodes = nodes
+  }
+}
+
+export class DynamicFragment extends VaporFragment {
+  anchor: Node
+  scope: EffectScope | undefined
+  current?: BlockFn
+  fallback?: BlockFn
+
+  constructor(anchorLabel?: string) {
+    super([])
+    this.anchor =
+      __DEV__ && anchorLabel ? createComment(anchorLabel) : createTextNode()
+  }
+
+  update(render?: BlockFn, key: any = render): void {
+    if (key === this.current) {
+      return
+    }
+    this.current = key
+
+    pauseTracking()
+    const parent = this.anchor.parentNode
+
+    // teardown previous branch
+    if (this.scope) {
+      this.scope.stop()
+      parent && remove(this.nodes, parent)
+    }
+
+    if (render) {
+      this.scope = new EffectScope()
+      this.nodes = this.scope.run(render) || []
+      if (parent) insert(this.nodes, parent, this.anchor)
+    } else {
+      this.scope = undefined
+      this.nodes = []
+    }
+
+    if (this.fallback && !isValidBlock(this.nodes)) {
+      parent && remove(this.nodes, parent)
+      this.nodes =
+        (this.scope || (this.scope = new EffectScope())).run(this.fallback) ||
+        []
+      parent && insert(this.nodes, parent, this.anchor)
+    }
+
+    resetTracking()
+  }
+}
+
+export function isFragment(val: NonNullable<unknown>): val is VaporFragment {
+  return val instanceof VaporFragment
+}
index 2edceb5491232e493dedf7b1c5a57298547e3bb0..c2716059df282640a4e65b1b495d05d370e0a9d3 100644 (file)
@@ -6,7 +6,7 @@ export type { VaporDirective } from './directives/custom'
 export { VaporTeleport } from './components/Teleport'
 
 // compiler-use only
-export { insert, prepend, remove, isFragment, VaporFragment } from './block'
+export { insert, prepend, remove } from './block'
 export { setInsertionState } from './insertionState'
 export { createComponent, createComponentWithFallback } from './component'
 export { renderEffect } from './renderEffect'
@@ -43,3 +43,5 @@ export {
   applyDynamicModel,
 } from './directives/vModel'
 export { withVaporDirectives } from './directives/custom'
+export { isFragment } from './fragment'
+export { VaporFragment } from './fragment'
index 77228fd72a02fe85a5496daf7d89bc37e197a4d2..2249bbb2fdcdcf4ec1ef49eabb5d9221cbb4df51 100644 (file)
@@ -26,13 +26,14 @@ import {
   mountComponent,
   unmountComponent,
 } from './component'
-import { type Block, VaporFragment, insert, remove } from './block'
+import { type Block, insert, remove } from './block'
 import { EMPTY_OBJ, extend, isFunction } from '@vue/shared'
 import { type RawProps, rawPropsProxyHandlers } from './componentProps'
 import type { RawSlots, VaporSlot } from './componentSlots'
 import { renderEffect } from './renderEffect'
 import { createTextNode } from './dom/node'
 import { optimizePropertyLookup } from './dom/prop'
+import { VaporFragment } from './fragment'
 
 // mounting vapor components and slots in vdom
 const vaporInteropImpl: Omit<