Skip to content

Commit 18970f2

Browse files
committed
wip: vdom interop
1 parent d281d62 commit 18970f2

File tree

7 files changed

+80
-59
lines changed

7 files changed

+80
-59
lines changed

packages/runtime-core/src/apiCreateApp.ts

-3
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ import type { NormalizedPropsOptions } from './componentProps'
3333
import type { ObjectEmitsOptions } from './componentEmits'
3434
import { ErrorCodes, callWithAsyncErrorHandling } from './errorHandling'
3535
import type { DefineComponent } from './apiDefineComponent'
36-
import type { createHydrationFunctions } from './hydration'
3736

3837
export interface App<HostElement = any> {
3938
version: string
@@ -105,7 +104,6 @@ export interface App<HostElement = any> {
105104
_container: HostElement | null
106105
_context: AppContext
107106
_instance: GenericComponentInstance | null
108-
_ssr?: boolean
109107

110108
/**
111109
* @internal custom element vnode
@@ -206,7 +204,6 @@ export interface VaporInteropInterface {
206204
parentComponent: any, // VaporComponentInstance
207205
fallback?: any, // VaporSlot
208206
) => any
209-
vdomHydrate: ReturnType<typeof createHydrationFunctions>[1] | undefined
210207
}
211208

212209
/**

packages/runtime-dom/src/index.ts

-1
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,6 @@ export const createApp = ((...args) => {
149149

150150
export const createSSRApp = ((...args) => {
151151
const app = ensureHydrationRenderer().createApp(...args)
152-
app._ssr = true
153152

154153
if (__DEV__) {
155154
injectNativeTagCheck(app)

packages/runtime-vapor/__tests__/hydration.spec.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -3838,7 +3838,7 @@ describe('Vapor Mode hydration', () => {
38383838
})
38393839

38403840
describe('VDOM hydration interop', () => {
3841-
test('basic component', async () => {
3841+
test('basic vapor component', async () => {
38423842
const data = ref(true)
38433843
const { container } = await testHydration(
38443844
`<script setup>const data = _data; const components = _components;</script>
@@ -3891,7 +3891,7 @@ describe('VDOM hydration interop', () => {
38913891
expect(container.innerHTML).toMatchInlineSnapshot(`"false"`)
38923892
})
38933893

3894-
test.todo('slots', async () => {
3894+
test('vapor slot render vdom component', async () => {
38953895
const data = ref(true)
38963896
const { container } = await testHydration(
38973897
`<script setup>const data = _data; const components = _components;</script>

packages/runtime-vapor/src/block.ts

-1
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,6 @@ export function insert(
154154
} else {
155155
// fragment
156156
if (block.insert) {
157-
// TODO handle hydration for vdom interop
158157
block.insert(parent, anchor)
159158
} else {
160159
insert(block.nodes, parent, anchor)

packages/runtime-vapor/src/component.ts

+5-16
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,7 @@ import {
5858
getSlot,
5959
} from './componentSlots'
6060
import { hmrReload, hmrRerender } from './hmr'
61-
import {
62-
currentHydrationNode,
63-
isHydrating,
64-
locateHydrationNode,
65-
} from './dom/hydration'
61+
import { isHydrating, locateHydrationNode } from './dom/hydration'
6662
import {
6763
insertionAnchor,
6864
insertionParent,
@@ -156,22 +152,15 @@ export function createComponent(
156152

157153
// vdom interop enabled and component is not an explicit vapor component
158154
if (appContext.vapor && !component.__vapor) {
159-
const [frag, vnode] = appContext.vapor.vdomMount(
155+
const frag = appContext.vapor.vdomMount(
160156
component as any,
161157
rawProps,
162158
rawSlots,
163159
)
164-
if (!isHydrating && _insertionParent) {
160+
161+
// `frag.insert` handles both hydration and mounting
162+
if (_insertionParent) {
165163
insert(frag, _insertionParent, _insertionAnchor)
166-
} else if (isHydrating) {
167-
appContext.vapor.vdomHydrate!(
168-
currentHydrationNode!,
169-
vnode,
170-
currentInstance as any,
171-
null,
172-
null,
173-
false,
174-
)
175164
}
176165
return frag
177166
}

packages/runtime-vapor/src/componentSlots.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,6 @@ export function createSlot(
114114
: EMPTY_OBJ
115115

116116
let fragment: DynamicFragment
117-
118117
if (isRef(rawSlots._)) {
119118
fragment = instance.appContext.vapor!.vdomSlot(
120119
rawSlots._,
@@ -157,7 +156,12 @@ export function createSlot(
157156
}
158157
}
159158

160-
if (!isHydrating && _insertionParent) {
159+
if (
160+
_insertionParent &&
161+
(!isHydrating ||
162+
// for vdom interop fragment, `fragment.insert` handles both hydration and mounting
163+
fragment.insert)
164+
) {
161165
insert(fragment, _insertionParent, _insertionAnchor)
162166
}
163167

packages/runtime-vapor/src/vdomInterop.ts

+67-34
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,17 @@ import type { RawSlots, VaporSlot } from './componentSlots'
3535
import { renderEffect } from './renderEffect'
3636
import { createTextNode } from './dom/node'
3737
import { optimizePropertyLookup } from './dom/prop'
38-
import { hydrateNode as vaporHydrateNode } from './dom/hydration'
38+
import {
39+
currentHydrationNode,
40+
isHydrating,
41+
locateHydrationNode,
42+
hydrateNode as vaporHydrateNode,
43+
} from './dom/hydration'
3944

4045
// mounting vapor components and slots in vdom
4146
const vaporInteropImpl: Omit<
4247
VaporInteropInterface,
43-
'vdomMount' | 'vdomUnmount' | 'vdomSlot' | 'vdomHydrate'
48+
'vdomMount' | 'vdomUnmount' | 'vdomSlot'
4449
> = {
4550
mount(vnode, container, anchor, parentComponent) {
4651
const selfAnchor = (vnode.el = vnode.anchor = createTextNode())
@@ -144,6 +149,8 @@ const vaporSlotsProxyHandler: ProxyHandler<any> = {
144149
},
145150
}
146151

152+
let vdomHydrateNode: HydrationRenderer['hydrateNode'] | undefined
153+
147154
/**
148155
* Mount vdom component in vapor
149156
*/
@@ -152,7 +159,7 @@ function createVDOMComponent(
152159
component: ConcreteComponent,
153160
rawProps?: LooseRawProps | null,
154161
rawSlots?: LooseRawSlots | null,
155-
): [VaporFragment, VNode] {
162+
): VaporFragment {
156163
const frag = new VaporFragment([])
157164
const vnode = createVNode(
158165
component,
@@ -181,16 +188,30 @@ function createVDOMComponent(
181188
}
182189

183190
frag.insert = (parentNode, anchor) => {
184-
if (!isMounted) {
185-
internals.mt(
186-
vnode,
187-
parentNode,
188-
anchor,
189-
parentInstance as any,
190-
null,
191-
undefined,
192-
false,
193-
)
191+
if (!isMounted || isHydrating) {
192+
if (isHydrating) {
193+
;(
194+
vdomHydrateNode ||
195+
(vdomHydrateNode = ensureHydrationRenderer().hydrateNode!)
196+
)(
197+
currentHydrationNode!,
198+
vnode,
199+
parentInstance as any,
200+
null,
201+
null,
202+
false,
203+
)
204+
} else {
205+
internals.mt(
206+
vnode,
207+
parentNode,
208+
anchor,
209+
parentInstance as any,
210+
null,
211+
undefined,
212+
false,
213+
)
214+
}
194215
onScopeDispose(unmount, true)
195216
isMounted = true
196217
} else {
@@ -207,7 +228,7 @@ function createVDOMComponent(
207228

208229
frag.remove = unmount
209230

210-
return [frag, vnode]
231+
return frag
211232
}
212233

213234
/**
@@ -235,28 +256,43 @@ function renderVDOMSlot(
235256
isFunction(name) ? name() : name,
236257
props,
237258
)
238-
if ((vnode.children as any[]).length) {
239-
if (fallbackNodes) {
240-
remove(fallbackNodes, parentNode)
241-
fallbackNodes = undefined
242-
}
243-
internals.p(
244-
oldVNode,
259+
if (isHydrating) {
260+
locateHydrationNode(true)
261+
;(
262+
vdomHydrateNode ||
263+
(vdomHydrateNode = ensureHydrationRenderer().hydrateNode!)
264+
)(
265+
currentHydrationNode!,
245266
vnode,
246-
parentNode,
247-
anchor,
248267
parentComponent as any,
268+
null,
269+
null,
270+
false,
249271
)
250-
oldVNode = vnode
251272
} else {
252-
if (fallback && !fallbackNodes) {
253-
// mount fallback
254-
if (oldVNode) {
255-
internals.um(oldVNode, parentComponent as any, null, true)
273+
if ((vnode.children as any[]).length) {
274+
if (fallbackNodes) {
275+
remove(fallbackNodes, parentNode)
276+
fallbackNodes = undefined
277+
}
278+
internals.p(
279+
oldVNode,
280+
vnode,
281+
parentNode,
282+
anchor,
283+
parentComponent as any,
284+
)
285+
oldVNode = vnode
286+
} else {
287+
if (fallback && !fallbackNodes) {
288+
// mount fallback
289+
if (oldVNode) {
290+
internals.um(oldVNode, parentComponent as any, null, true)
291+
}
292+
insert((fallbackNodes = fallback(props)), parentNode, anchor)
256293
}
257-
insert((fallbackNodes = fallback(props)), parentNode, anchor)
294+
oldVNode = null
258295
}
259-
oldVNode = null
260296
}
261297
})
262298
isMounted = true
@@ -284,14 +320,11 @@ function renderVDOMSlot(
284320
}
285321

286322
export const vaporInteropPlugin: Plugin = app => {
287-
const { internals, hydrateNode } = (
288-
app._ssr ? ensureHydrationRenderer() : ensureRenderer()
289-
) as HydrationRenderer
323+
const internals = ensureRenderer().internals
290324
app._context.vapor = extend(vaporInteropImpl, {
291325
vdomMount: createVDOMComponent.bind(null, internals),
292326
vdomUnmount: internals.umt,
293327
vdomSlot: renderVDOMSlot.bind(null, internals),
294-
vdomHydrate: hydrateNode,
295328
})
296329
const mount = app.mount
297330
app.mount = ((...args) => {

0 commit comments

Comments
 (0)