diff --git a/packages/runtime-core/src/hydration.ts b/packages/runtime-core/src/hydration.ts index e8207cc0..e33b7548 100644 --- a/packages/runtime-core/src/hydration.ts +++ b/packages/runtime-core/src/hydration.ts @@ -14,6 +14,11 @@ import { warn } from './warning' import { PatchFlags, ShapeFlags, isReservedProp, isOn } from '@vue/shared' import { RendererOptions } from './renderer' +export type RootHydrateFunction = ( + vnode: VNode, + container: Element +) => void + // Note: hydration is DOM-specific // But we have to place it in core due to tight coupling with core - splitting // it out creates a ton of unnecessary complexity. @@ -23,7 +28,7 @@ export function createHydrationFunctions( mountComponent: any, // TODO patchProp: RendererOptions['patchProp'] ) { - const hydrate = (vnode: VNode, container: Element) => { + const hydrate: RootHydrateFunction = (vnode, container) => { if (__DEV__ && !container.hasChildNodes()) { warn(`Attempting to hydrate existing markup but container is empty.`) return diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index 25f1939f..f78c61a8 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -179,7 +179,13 @@ export { ComponentOptionsWithArrayProps } from './apiOptions' export { ComponentPublicInstance } from './componentProxy' -export { RendererOptions, RootRenderFunction } from './renderer' +export { + Renderer, + HydrationRenderer, + RendererOptions, + RootRenderFunction +} from './renderer' +export { RootHydrateFunction } from './hydration' export { Slot, Slots } from './componentSlots' export { Prop, diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index 6a0fb55f..a798178a 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -62,10 +62,24 @@ import { import { ErrorCodes, callWithErrorHandling } from './errorHandling' import { KeepAliveSink, isKeepAlive } from './components/KeepAlive' import { registerHMR, unregisterHMR } from './hmr' -import { createHydrationFunctions } from './hydration' +import { createHydrationFunctions, RootHydrateFunction } from './hydration' const __HMR__ = __BUNDLER__ && __DEV__ +export interface Renderer { + render: RootRenderFunction + createApp: CreateAppFunction +} + +export interface HydrationRenderer extends Renderer { + hydrate: RootHydrateFunction +} + +export type RootRenderFunction = ( + vnode: VNode | null, + container: HostElement +) => void + export interface RendererOptions { patchProp( el: HostElement, @@ -102,41 +116,6 @@ export interface RendererOptions { ): HostElement } -export type RootRenderFunction = ( - vnode: VNode | null, - dom: HostElement -) => void - -// 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 -} - export const enum MoveType { ENTER, LEAVE, @@ -186,25 +165,36 @@ export function createRenderer< HostNode extends object = any, HostElement extends HostNode = any >(options: RendererOptions) { - const res = baseCreateRenderer(options) - return res as typeof res & { - hydrate: undefined - } + return baseCreateRenderer(options) } // Separate API for creating hydration-enabled renderer. // Hydration logic is only used when calling this function, making it // tree-shakable. -export function createHydrationRenderer< - HostNode extends object = any, - HostElement extends HostNode = any ->(options: RendererOptions) { - const res = baseCreateRenderer(options, createHydrationFunctions) - return res as typeof res & { - hydrate: ReturnType[0] - } +export function createHydrationRenderer( + options: RendererOptions +) { + return baseCreateRenderer(options, createHydrationFunctions) } +// overload 1: no hydration +function baseCreateRenderer< + HostNode extends object = any, + HostElement extends HostNode = any +>( + options: RendererOptions +): Renderer + +// overload 2: with hydration +function baseCreateRenderer< + HostNode extends object = any, + HostElement extends HostNode = any +>( + options: RendererOptions, + createHydrationFns: typeof createHydrationFunctions +): HydrationRenderer + +// implementation function baseCreateRenderer< HostNode extends object = any, HostElement extends HostNode = any @@ -1862,6 +1852,36 @@ 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() diff --git a/packages/runtime-dom/src/index.ts b/packages/runtime-dom/src/index.ts index cda9c502..d3743e4f 100644 --- a/packages/runtime-dom/src/index.ts +++ b/packages/runtime-dom/src/index.ts @@ -4,8 +4,10 @@ import { warn, RootRenderFunction, CreateAppFunction, - VNode, - App + Renderer, + HydrationRenderer, + App, + RootHydrateFunction } from '@vue/runtime-core' import { nodeOps } from './nodeOps' import { patchProp } from './patchProp' @@ -19,9 +21,7 @@ const rendererOptions = { // lazy create the renderer - this makes core renderer logic tree-shakable // in case the user only imports reactivity utilities from Vue. -let renderer: - | ReturnType - | ReturnType +let renderer: Renderer | HydrationRenderer let enabledHydration = false @@ -34,7 +34,7 @@ function ensureHydrationRenderer() { ? renderer : createHydrationRenderer(rendererOptions) enabledHydration = true - return renderer as ReturnType + return renderer as HydrationRenderer } // use explicit type casts here to avoid import() calls in rolled-up d.ts @@ -44,7 +44,7 @@ export const render = ((...args) => { export const hydrate = ((...args) => { ensureHydrationRenderer().hydrate(...args) -}) as (vnode: VNode, container: Element) => void +}) as RootHydrateFunction export const createApp = ((...args) => { const app = ensureRenderer().createApp(...args)