import { ports } from '../utils'
const { page, click, html } = setupPuppeteer()
-describe('vdom / vapor interop', () => {
+describe('vapor teleport', () => {
let server: any
const port = ports.teleport
beforeAll(() => {
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,
+ )
})
-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')
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,
} 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'
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
-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,
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
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 ||
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[]
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,
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[])
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(() => {
} 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)) {
--- /dev/null
+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
+}
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'
applyDynamicModel,
} from './directives/vModel'
export { withVaporDirectives } from './directives/custom'
+export { isFragment } from './fragment'
+export { VaporFragment } from './fragment'
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<