export function createRenderer< HostNode extends object = any, HostElement extends HostNode = any >( options: RendererOptions<HostNode, HostElement> ): { render: RootRenderFunction<HostNode, HostElement> createApp: () => App<HostElement> } { type HostVNode = VNode<HostNode, HostElement> type HostVNodeChildren = VNodeChildren<HostNode, HostElement> type HostSuspenseBoundary = SuspenseBoundary<HostNode, HostElement> const { insert: hostInsert, remove: hostRemove, patchProp: hostPatchProp, createElement: hostCreateElement } = options function patch( n1: HostVNode | null, n2: HostVNode, container: HostElement, anchor: HostNode | null = null, parentComponent: ComponentInternalInstance | null = null, parentSuspense: HostSuspenseBoundary | null = null, isSVG: boolean = false, optimized: boolean = false ) { processComponent( n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized ) } function processComponent( n1: HostVNode | null, n2: HostVNode, container: HostElement, anchor: HostNode | null, parentComponent: ComponentInternalInstance | null, parentSuspense: HostSuspenseBoundary | null, isSVG: boolean, optimized: boolean ) { if (n1 == null) { mountComponent( n2, container, anchor, parentComponent, parentSuspense, isSVG ) } else { const instance = (n2.component = n1.component)! instance.update() } } function mountComponent( initialVNode: HostVNode, container: HostElement, anchor: HostNode | null, parentComponent: ComponentInternalInstance | null, parentSuspense: HostSuspenseBoundary | null, isSVG: boolean ) { const instance: ComponentInternalInstance = (initialVNode.component = createComponentInstance( initialVNode, parentComponent )) if (initialVNode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT) { setupStatefulComponent(instance, parentSuspense) } setupRenderEffect( instance, parentSuspense, initialVNode, container, anchor, isSVG ) } function setupRenderEffect( instance: ComponentInternalInstance, parentSuspense: HostSuspenseBoundary | null, initialVNode: HostVNode, container: HostElement, anchor: HostNode | null, isSVG: boolean ) { let mounted = false instance.update = effect(function componentEffect() { if (!mounted) { const subTree = (instance.subTree = renderComponentRoot(instance)) patch(null, subTree, container, anchor, instance, parentSuspense, isSVG) mounted = true } else { const { next } = instance const prevTree = instance.subTree const nextTree = (instance.subTree = renderComponentRoot(instance)) patch( prevTree, nextTree, hostParentNode(prevTree.el as HostNode) as HostElement, getNextHostNode(prevTree), instance, parentSuspense, isSVG ) } }, __DEV__ ? createDevEffectOptions(instance) : prodEffectOptions) } function render(vnode: HostVNode | null, rawContainer: HostElement | string) { let container: any = rawContainer if (vnode == null) { if (container._vnode) { unmount(container._vnode, null, null, true) } } else { patch(container._vnode || null, vnode, container) } flushPostFlushCbs() container._vnode = vnode } return { render, createApp: createAppAPI(render) } }
|