types: avoid duplicate type declarations for renderer closure functions

This commit is contained in:
Evan You 2020-02-14 16:25:41 -05:00
parent e0f3c6b352
commit 96605b79a3
3 changed files with 124 additions and 88 deletions

View File

@ -2,7 +2,7 @@ import { VNode, normalizeVNode, VNodeChild } from '../vnode'
import { isFunction, isArray, ShapeFlags } from '@vue/shared'
import { ComponentInternalInstance, handleSetupResult } from '../component'
import { Slots } from '../componentSlots'
import { RendererInternals, MoveType } from '../renderer'
import { RendererInternals, MoveType, SetupRenderEffectFn } from '../renderer'
import { queuePostFlushCb, queueJob } from '../scheduler'
import { updateHOCHostEl } from '../componentRenderUtils'
import { handleError, ErrorCodes } from '../errorHandling'
@ -216,14 +216,7 @@ export interface SuspenseBoundary<
next(): HostNode | null
registerDep(
instance: ComponentInternalInstance,
setupRenderEffect: (
instance: ComponentInternalInstance,
initialVNode: VNode<HostNode, HostElement>,
container: HostElement | null,
anchor: HostNode | null,
parentSuspense: SuspenseBoundary<HostNode, HostElement> | null,
isSVG: boolean
) => void
setupRenderEffect: SetupRenderEffectFn<HostNode, HostElement>
): void
unmount(
parentSuspense: SuspenseBoundary<HostNode, HostElement> | null,

View File

@ -12,7 +12,7 @@ import { ComponentInternalInstance } from './component'
import { invokeDirectiveHook } from './directives'
import { warn } from './warning'
import { PatchFlags, ShapeFlags, isReservedProp, isOn } from '@vue/shared'
import { RendererOptions } from './renderer'
import { RendererOptions, MountComponentFn } from './renderer'
export type RootHydrateFunction = (
vnode: VNode<Node, Element>,
@ -25,7 +25,7 @@ export type RootHydrateFunction = (
// Hydration also depends on some renderer internal logic which needs to be
// passed in via arguments.
export function createHydrationFunctions(
mountComponent: any, // TODO
mountComponent: MountComponentFn<Node, Element>,
patchProp: RendererOptions['patchProp']
) {
const hydrate: RootHydrateFunction = (vnode, container) => {
@ -68,6 +68,9 @@ export function createHydrationFunctions(
if (shapeFlag & ShapeFlags.ELEMENT) {
return hydrateElement(node as Element, vnode, parentComponent)
} else if (shapeFlag & ShapeFlags.COMPONENT) {
// when setting up the render effect, if the initial vnode already
// has .el set, the component will perform hydration instead of mount
// on its sub-tree.
mountComponent(vnode, null, null, parentComponent, null, false)
const subTree = vnode.component!.subTree
return (subTree.anchor || subTree.el).nextSibling

View File

@ -90,11 +90,7 @@ export interface RendererOptions<HostNode = any, HostElement = any> {
prevChildren?: VNode<HostNode, HostElement>[],
parentComponent?: ComponentInternalInstance | null,
parentSuspense?: SuspenseBoundary<HostNode, HostElement> | null,
unmountChildren?: (
children: VNode<HostNode, HostElement>[],
parentComponent: ComponentInternalInstance | null,
parentSuspense: SuspenseBoundary<HostNode, HostElement> | null
) => void
unmountChildren?: UnmountChildrenFn<HostNode, HostElement>
): void
insert(el: HostNode, parent: HostElement, anchor?: HostNode | null): void
remove(el: HostNode): void
@ -116,6 +112,75 @@ export interface RendererOptions<HostNode = any, HostElement = any> {
): HostElement
}
// An object exposing the internals of a renderer, passed to tree-shakeable
// features so that they can be decoupled from this file.
export interface RendererInternals<HostNode = any, HostElement = any> {
patch: PatchFn<HostNode, HostElement>
unmount: UnmountFn<HostNode, HostElement>
move: MoveFn<HostNode, HostElement>
next: NextFn<HostNode, HostElement>
options: RendererOptions<HostNode, HostElement>
}
// These functions are created inside a closure and therefore there types cannot
// be directly exported. In order to avoid maintaining function signatures in
// two places, we declare them once here and use them inside the closure.
type PatchFn<HostNode, HostElement> = (
n1: VNode<HostNode, HostElement> | null, // null means this is a mount
n2: VNode<HostNode, HostElement>,
container: HostElement,
anchor?: HostNode | null,
parentComponent?: ComponentInternalInstance | null,
parentSuspense?: SuspenseBoundary<HostNode, HostElement> | null,
isSVG?: boolean,
optimized?: boolean
) => void
type UnmountFn<HostNode, HostElement> = (
vnode: VNode<HostNode, HostElement>,
parentComponent: ComponentInternalInstance | null,
parentSuspense: SuspenseBoundary<HostNode, HostElement> | null,
doRemove?: boolean
) => void
type MoveFn<HostNode, HostElement> = (
vnode: VNode<HostNode, HostElement>,
container: HostElement,
anchor: HostNode | null,
type: MoveType,
parentSuspense?: SuspenseBoundary<HostNode, HostElement> | null
) => void
type NextFn<HostNode, HostElement> = (
vnode: VNode<HostNode, HostElement>
) => HostNode | null
type UnmountChildrenFn<HostNode, HostElement> = (
children: VNode<HostNode, HostElement>[],
parentComponent: ComponentInternalInstance | null,
parentSuspense: SuspenseBoundary<HostNode, HostElement> | null,
doRemove?: boolean,
start?: number
) => void
export type MountComponentFn<HostNode, HostElement> = (
initialVNode: VNode<HostNode, HostElement>,
container: HostElement | null, // only null during hydration
anchor: HostNode | null,
parentComponent: ComponentInternalInstance | null,
parentSuspense: SuspenseBoundary<HostNode, HostElement> | null,
isSVG: boolean
) => void
export type SetupRenderEffectFn<HostNode, HostElement> = (
instance: ComponentInternalInstance,
initialVNode: VNode<HostNode, HostElement>,
container: HostElement | null, // only null during hydration
anchor: HostNode | null,
parentSuspense: SuspenseBoundary<HostNode, HostElement> | null,
isSVG: boolean
) => void
export const enum MoveType {
ENTER,
LEAVE,
@ -223,15 +288,17 @@ function baseCreateRenderer<
insertStaticContent: hostInsertStaticContent
} = options
const patch = (
n1: HostVNode | null, // null means this is a mount
n2: HostVNode,
container: HostElement,
anchor: HostNode | null = null,
parentComponent: ComponentInternalInstance | null = null,
parentSuspense: HostSuspenseBoundary | null = null,
isSVG: boolean = false,
optimized: boolean = false
// Note: functions inside this closure should use `const xxx = () => {}`
// style in order to prevent being inlined by minifiers.
const patch: PatchFn<HostNode, HostElement> = (
n1,
n2,
container,
anchor = null,
parentComponent = null,
parentSuspense = null,
isSVG = false,
optimized = false
) => {
// patching & not same type, unmount old tree
if (n1 != null && !isSameVNodeType(n1, n2)) {
@ -984,13 +1051,13 @@ function baseCreateRenderer<
}
}
const mountComponent = (
initialVNode: HostVNode,
container: HostElement | null, // only null during hydration
anchor: HostNode | null,
parentComponent: ComponentInternalInstance | null,
parentSuspense: HostSuspenseBoundary | null,
isSVG: boolean
const mountComponent: MountComponentFn<HostNode, HostElement> = (
initialVNode,
container, // only null during hydration
anchor,
parentComponent,
parentSuspense,
isSVG
) => {
const instance: ComponentInternalInstance = (initialVNode.component = createComponentInstance(
initialVNode,
@ -1046,13 +1113,13 @@ function baseCreateRenderer<
}
}
const setupRenderEffect = (
instance: ComponentInternalInstance,
initialVNode: HostVNode,
container: HostElement | null, // only null during hydration
anchor: HostNode | null,
parentSuspense: HostSuspenseBoundary | null,
isSVG: boolean
const setupRenderEffect: SetupRenderEffectFn<HostNode, HostElement> = (
instance,
initialVNode,
container,
anchor,
parentSuspense,
isSVG
) => {
// create reactive effect for rendering
instance.update = effect(function componentEffect() {
@ -1545,12 +1612,12 @@ function baseCreateRenderer<
}
}
const move = (
vnode: HostVNode,
container: HostElement,
anchor: HostNode | null,
type: MoveType,
parentSuspense: HostSuspenseBoundary | null = null
const move: MoveFn<HostNode, HostElement> = (
vnode,
container,
anchor,
type,
parentSuspense = null
) => {
if (vnode.shapeFlag & ShapeFlags.COMPONENT) {
move(vnode.component!.subTree, container, anchor, type)
@ -1600,11 +1667,11 @@ function baseCreateRenderer<
}
}
const unmount = (
vnode: HostVNode,
parentComponent: ComponentInternalInstance | null,
parentSuspense: HostSuspenseBoundary | null,
doRemove?: boolean
const unmount: UnmountFn<HostNode, HostElement> = (
vnode,
parentComponent,
parentSuspense,
doRemove = false
) => {
const { props, ref, children, dynamicChildren, shapeFlag } = vnode
@ -1755,19 +1822,19 @@ function baseCreateRenderer<
}
}
const unmountChildren = (
children: HostVNode[],
parentComponent: ComponentInternalInstance | null,
parentSuspense: HostSuspenseBoundary | null,
doRemove?: boolean,
start: number = 0
const unmountChildren: UnmountChildrenFn<HostNode, HostElement> = (
children,
parentComponent,
parentSuspense,
doRemove = false,
start = 0
) => {
for (let i = start; i < children.length; i++) {
unmount(children[i], parentComponent, parentSuspense, doRemove)
}
}
const getNextHostNode = (vnode: HostVNode): HostNode | null => {
const getNextHostNode: NextFn<HostNode, HostElement> = vnode => {
if (vnode.shapeFlag & ShapeFlags.COMPONENT) {
return getNextHostNode(vnode.component!.subTree)
}
@ -1842,7 +1909,10 @@ function baseCreateRenderer<
let hydrate: ReturnType<typeof createHydrationFunctions>[0] | undefined
let hydrateNode: ReturnType<typeof createHydrationFunctions>[1] | undefined
if (createHydrationFns) {
;[hydrate, hydrateNode] = createHydrationFns(mountComponent, hostPatchProp)
;[hydrate, hydrateNode] = createHydrationFns(
mountComponent as MountComponentFn<Node, Element>,
hostPatchProp
)
}
return {
@ -1852,36 +1922,6 @@ function baseCreateRenderer<
}
}
// An object exposing the internals of a renderer, passed to tree-shakeable
// features so that they can be decoupled from this file.
export interface RendererInternals<HostNode = any, HostElement = any> {
patch: (
n1: VNode<HostNode, HostElement> | null, // null means this is a mount
n2: VNode<HostNode, HostElement>,
container: HostElement,
anchor?: HostNode | null,
parentComponent?: ComponentInternalInstance | null,
parentSuspense?: SuspenseBoundary<HostNode, HostElement> | null,
isSVG?: boolean,
optimized?: boolean
) => void
unmount: (
vnode: VNode<HostNode, HostElement>,
parentComponent: ComponentInternalInstance | null,
parentSuspense: SuspenseBoundary<HostNode, HostElement> | null,
doRemove?: boolean
) => void
move: (
vnode: VNode<HostNode, HostElement>,
container: HostElement,
anchor: HostNode | null,
type: MoveType,
parentSuspense?: SuspenseBoundary<HostNode, HostElement> | null
) => void
next: (vnode: VNode<HostNode, HostElement>) => HostNode | null
options: RendererOptions<HostNode, HostElement>
}
// https://en.wikipedia.org/wiki/Longest_increasing_subsequence
function getSequence(arr: number[]): number[] {
const p = arr.slice()