Skip to content

Commit e1f5482

Browse files
committed
wip: vdom interop
1 parent 700f49e commit e1f5482

File tree

5 files changed

+50
-18
lines changed

5 files changed

+50
-18
lines changed

packages/runtime-core/src/apiCreateApp.ts

+1
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ export interface VaporInteropInterface {
193193
unmount(vnode: VNode, doRemove?: boolean): void
194194
move(vnode: VNode, container: any, anchor: any): void
195195
slot(n1: VNode | null, n2: VNode, container: any, anchor: any): void
196+
hydrate(node: Node, fn: () => void): void
196197

197198
vdomMount: (component: ConcreteComponent, props?: any, slots?: any) => any
198199
vdomUnmount: UnmountComponentFn

packages/runtime-core/src/hydration.ts

+22-14
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,11 @@ import {
3737
normalizeStyle,
3838
stringifyStyle,
3939
} from '@vue/shared'
40-
import { type RendererInternals, needTransition } from './renderer'
40+
import {
41+
type RendererInternals,
42+
getVaporInterface,
43+
needTransition,
44+
} from './renderer'
4145
import { setRef } from './rendererTemplateRef'
4246
import {
4347
type SuspenseBoundary,
@@ -294,10 +298,6 @@ export function createHydrationFunctions(
294298
)
295299
}
296300
} else if (shapeFlag & ShapeFlags.COMPONENT) {
297-
if ((vnode.type as ConcreteComponent).__vapor) {
298-
throw new Error('Vapor component hydration is not supported yet.')
299-
}
300-
301301
// when setting up the render effect, if the initial vnode already
302302
// has .el set, the component will perform hydration instead of mount
303303
// on its sub-tree.
@@ -318,15 +318,23 @@ export function createHydrationFunctions(
318318
nextNode = nextSibling(node)
319319
}
320320

321-
mountComponent(
322-
vnode,
323-
container,
324-
null,
325-
parentComponent,
326-
parentSuspense,
327-
getContainerType(container),
328-
optimized,
329-
)
321+
// hydrate vapor component
322+
if ((vnode.type as ConcreteComponent).__vapor) {
323+
const vaporInterface = getVaporInterface(parentComponent, vnode)
324+
vaporInterface.hydrate(node, () => {
325+
vaporInterface.mount(vnode, container, null, parentComponent)
326+
})
327+
} else {
328+
mountComponent(
329+
vnode,
330+
container,
331+
null,
332+
parentComponent,
333+
parentSuspense,
334+
getContainerType(container),
335+
optimized,
336+
)
337+
}
330338

331339
// #3787
332340
// if component is async, it may get moved / unmounted before its

packages/runtime-core/src/renderer.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -2639,7 +2639,10 @@ export function invalidateMount(hooks: LifecycleHook | undefined): void {
26392639
}
26402640
}
26412641

2642-
function getVaporInterface(
2642+
/**
2643+
* @internal
2644+
*/
2645+
export function getVaporInterface(
26432646
instance: ComponentInternalInstance | null,
26442647
vnode: VNode,
26452648
): VaporInteropInterface {

packages/runtime-vapor/src/dom/hydration.ts

+20-3
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@ export function setCurrentHydrationNode(node: Node | null): void {
2222

2323
let isOptimized = false
2424

25-
export function withHydration(container: ParentNode, fn: () => void): void {
25+
function performHydration<T>(
26+
fn: () => T,
27+
setup: () => void,
28+
cleanup: () => void,
29+
): T {
2630
adoptTemplate = adoptTemplateImpl
2731
locateHydrationNode = locateHydrationNodeImpl
2832
if (!isOptimized) {
@@ -33,15 +37,28 @@ export function withHydration(container: ParentNode, fn: () => void): void {
3337
}
3438
enableHydrationNodeLookup()
3539
isHydrating = true
36-
setInsertionState(container, 0)
40+
41+
setup()
3742
const res = fn()
38-
resetInsertionState()
43+
cleanup()
3944
currentHydrationNode = null
4045
isHydrating = false
4146
disableHydrationNodeLookup()
4247
return res
4348
}
4449

50+
export function withHydration(container: ParentNode, fn: () => void): void {
51+
const setup = () => setInsertionState(container, 0)
52+
const cleanup = () => resetInsertionState()
53+
return performHydration(fn, setup, cleanup)
54+
}
55+
56+
export function hydrateNode(node: Node, fn: () => void): void {
57+
const setup = () => (currentHydrationNode = node)
58+
const cleanup = () => {}
59+
return performHydration(fn, setup, cleanup)
60+
}
61+
4562
export let adoptTemplate: (node: Node, template: string) => Node | null
4663
export let locateHydrationNode: (hasFragmentAnchor?: boolean) => void
4764

packages/runtime-vapor/src/vdomInterop.ts

+3
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import type { RawSlots, VaporSlot } from './componentSlots'
3333
import { renderEffect } from './renderEffect'
3434
import { createTextNode } from './dom/node'
3535
import { optimizePropertyLookup } from './dom/prop'
36+
import { hydrateNode as vaporHydrateNode } from './dom/hydration'
3637

3738
// mounting vapor components and slots in vdom
3839
const vaporInteropImpl: Omit<
@@ -113,6 +114,8 @@ const vaporInteropImpl: Omit<
113114
insert(vnode.vb || (vnode.component as any), container, anchor)
114115
insert(vnode.anchor as any, container, anchor)
115116
},
117+
118+
hydrate: vaporHydrateNode,
116119
}
117120

118121
const vaporSlotPropsProxyHandler: ProxyHandler<

0 commit comments

Comments
 (0)