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