From 96605b79a3224c069099418a048a6388abed7e1f Mon Sep 17 00:00:00 2001 From: Evan You Date: Fri, 14 Feb 2020 16:25:41 -0500 Subject: [PATCH] types: avoid duplicate type declarations for renderer closure functions --- .../runtime-core/src/components/Suspense.ts | 11 +- packages/runtime-core/src/hydration.ts | 7 +- packages/runtime-core/src/renderer.ts | 194 +++++++++++------- 3 files changed, 124 insertions(+), 88 deletions(-) diff --git a/packages/runtime-core/src/components/Suspense.ts b/packages/runtime-core/src/components/Suspense.ts index 211e5f30a..c8f7d5abc 100644 --- a/packages/runtime-core/src/components/Suspense.ts +++ b/packages/runtime-core/src/components/Suspense.ts @@ -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, - container: HostElement | null, - anchor: HostNode | null, - parentSuspense: SuspenseBoundary | null, - isSVG: boolean - ) => void + setupRenderEffect: SetupRenderEffectFn ): void unmount( parentSuspense: SuspenseBoundary | null, diff --git a/packages/runtime-core/src/hydration.ts b/packages/runtime-core/src/hydration.ts index e33b75487..bb9b80af7 100644 --- a/packages/runtime-core/src/hydration.ts +++ b/packages/runtime-core/src/hydration.ts @@ -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, @@ -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, 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 diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index a798178ad..dce719fa2 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -90,11 +90,7 @@ export interface RendererOptions { prevChildren?: VNode[], parentComponent?: ComponentInternalInstance | null, parentSuspense?: SuspenseBoundary | null, - unmountChildren?: ( - children: VNode[], - parentComponent: ComponentInternalInstance | null, - parentSuspense: SuspenseBoundary | null - ) => void + unmountChildren?: UnmountChildrenFn ): void insert(el: HostNode, parent: HostElement, anchor?: HostNode | null): void remove(el: HostNode): void @@ -116,6 +112,75 @@ export interface RendererOptions { ): 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 { + patch: PatchFn + unmount: UnmountFn + move: MoveFn + next: NextFn + options: RendererOptions +} + +// 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 = ( + n1: VNode | null, // null means this is a mount + n2: VNode, + container: HostElement, + anchor?: HostNode | null, + parentComponent?: ComponentInternalInstance | null, + parentSuspense?: SuspenseBoundary | null, + isSVG?: boolean, + optimized?: boolean +) => void + +type UnmountFn = ( + vnode: VNode, + parentComponent: ComponentInternalInstance | null, + parentSuspense: SuspenseBoundary | null, + doRemove?: boolean +) => void + +type MoveFn = ( + vnode: VNode, + container: HostElement, + anchor: HostNode | null, + type: MoveType, + parentSuspense?: SuspenseBoundary | null +) => void + +type NextFn = ( + vnode: VNode +) => HostNode | null + +type UnmountChildrenFn = ( + children: VNode[], + parentComponent: ComponentInternalInstance | null, + parentSuspense: SuspenseBoundary | null, + doRemove?: boolean, + start?: number +) => void + +export type MountComponentFn = ( + initialVNode: VNode, + container: HostElement | null, // only null during hydration + anchor: HostNode | null, + parentComponent: ComponentInternalInstance | null, + parentSuspense: SuspenseBoundary | null, + isSVG: boolean +) => void + +export type SetupRenderEffectFn = ( + instance: ComponentInternalInstance, + initialVNode: VNode, + container: HostElement | null, // only null during hydration + anchor: HostNode | null, + parentSuspense: SuspenseBoundary | 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 = ( + 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 = ( + 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 = ( + 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 = ( + 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 = ( + 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 = ( + 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 = vnode => { if (vnode.shapeFlag & ShapeFlags.COMPONENT) { return getNextHostNode(vnode.component!.subTree) } @@ -1842,7 +1909,10 @@ function baseCreateRenderer< let hydrate: ReturnType[0] | undefined let hydrateNode: ReturnType[1] | undefined if (createHydrationFns) { - ;[hydrate, hydrateNode] = createHydrationFns(mountComponent, hostPatchProp) + ;[hydrate, hydrateNode] = createHydrationFns( + mountComponent as MountComponentFn, + 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 { - patch: ( - n1: VNode | null, // null means this is a mount - n2: VNode, - container: HostElement, - anchor?: HostNode | null, - parentComponent?: ComponentInternalInstance | null, - parentSuspense?: SuspenseBoundary | null, - isSVG?: boolean, - optimized?: boolean - ) => void - unmount: ( - vnode: VNode, - parentComponent: ComponentInternalInstance | null, - parentSuspense: SuspenseBoundary | null, - doRemove?: boolean - ) => void - move: ( - vnode: VNode, - container: HostElement, - anchor: HostNode | null, - type: MoveType, - parentSuspense?: SuspenseBoundary | null - ) => void - next: (vnode: VNode) => HostNode | null - options: RendererOptions -} - // https://en.wikipedia.org/wiki/Longest_increasing_subsequence function getSequence(arr: number[]): number[] { const p = arr.slice()