import { invokeDirectiveHook } from './directives'
import { warn } from './warning'
import { PatchFlags, ShapeFlags, isReservedProp, isOn } from '@vue/shared'
+import { RendererOptions } from './renderer'
// Note: hydration is DOM-specific
// But we have to place it in core due to tight coupling with core - splitting
// passed in via arguments.
export function createHydrationFunctions(
mountComponent: any, // TODO
- patchProp: any // TODO
+ patchProp: RendererOptions['patchProp']
) {
- function hydrate(vnode: VNode, container: Element) {
+ const hydrate = (vnode: VNode, container: Element) => {
if (__DEV__ && !container.hasChildNodes()) {
warn(`Attempting to hydrate existing markup but container is empty.`)
return
// TODO handle mismatches
// TODO SVG
// TODO Suspense
- function hydrateNode(
+ const hydrateNode = (
node: Node,
vnode: VNode,
parentComponent: ComponentInternalInstance | null = null
- ): Node | null | undefined {
+ ): Node | null | undefined => {
const { type, shapeFlag } = vnode
vnode.el = node
switch (type) {
}
}
- function hydrateElement(
+ const hydrateElement = (
el: Element,
vnode: VNode,
parentComponent: ComponentInternalInstance | null
- ) {
+ ) => {
const { props, patchFlag } = vnode
// skip props & children if this is hoisted static nodes
if (patchFlag !== PatchFlags.HOISTED) {
return el.nextSibling
}
- function hydrateChildren(
+ const hydrateChildren = (
node: Node | null | undefined,
vnodes: VNode[],
parentComponent: ComponentInternalInstance | null
- ): Node | null | undefined {
+ ): Node | null | undefined => {
for (let i = 0; node != null && i < vnodes.length; i++) {
// TODO can skip normalizeVNode in optimized mode
// (need hint on rendered markup?)
insertStaticContent: hostInsertStaticContent
} = options
- const internals: RendererInternals<HostNode, HostElement> = {
- patch,
- unmount,
- move,
- next: getNextHostNode,
- options
- }
-
- let hydrate: ReturnType<typeof createHydrationFunctions>[0] | undefined
- let hydrateNode: ReturnType<typeof createHydrationFunctions>[1] | undefined
- if (createHydrationFns) {
- ;[hydrate, hydrateNode] = createHydrationFns(mountComponent, hostPatchProp)
- }
-
- function patch(
+ const patch = (
n1: HostVNode | null, // null means this is a mount
n2: HostVNode,
container: HostElement,
parentSuspense: HostSuspenseBoundary | null = null,
isSVG: boolean = false,
optimized: boolean = false
- ) {
+ ) => {
// patching & not same type, unmount old tree
if (n1 != null && !isSameVNodeType(n1, n2)) {
anchor = getNextHostNode(n1)
}
}
- function processText(
+ const processText = (
n1: HostVNode | null,
n2: HostVNode,
container: HostElement,
anchor: HostNode | null
- ) {
+ ) => {
if (n1 == null) {
hostInsert(
(n2.el = hostCreateText(n2.children as string)),
}
}
- function processCommentNode(
+ const processCommentNode = (
n1: HostVNode | null,
n2: HostVNode,
container: HostElement,
anchor: HostNode | null
- ) {
+ ) => {
if (n1 == null) {
hostInsert(
(n2.el = hostCreateComment((n2.children as string) || '')),
}
}
- function mountStaticNode(
+ const mountStaticNode = (
n2: HostVNode,
container: HostElement,
anchor: HostNode | null,
isSVG: boolean
- ) {
+ ) => {
if (n2.el != null && hostCloneNode !== undefined) {
hostInsert(hostCloneNode(n2.el), container, anchor)
} else {
}
}
- function processElement(
+ const processElement = (
n1: HostVNode | null,
n2: HostVNode,
container: HostElement,
parentSuspense: HostSuspenseBoundary | null,
isSVG: boolean,
optimized: boolean
- ) {
+ ) => {
isSVG = isSVG || (n2.type as string) === 'svg'
if (n1 == null) {
mountElement(
}
}
- function mountElement(
+ const mountElement = (
vnode: HostVNode,
container: HostElement,
anchor: HostNode | null,
parentSuspense: HostSuspenseBoundary | null,
isSVG: boolean,
optimized: boolean
- ) {
+ ) => {
let el: HostElement
const { type, props, shapeFlag, transition, scopeId, patchFlag } = vnode
if (
}
}
- function mountChildren(
+ const mountChildren = (
children: HostVNodeChildren,
container: HostElement,
anchor: HostNode | null,
isSVG: boolean,
optimized: boolean,
start: number = 0
- ) {
+ ) => {
for (let i = start; i < children.length; i++) {
const child = (children[i] = optimized
? cloneIfMounted(children[i] as HostVNode)
}
}
- function patchElement(
+ const patchElement = (
n1: HostVNode,
n2: HostVNode,
parentComponent: ComponentInternalInstance | null,
parentSuspense: HostSuspenseBoundary | null,
isSVG: boolean,
optimized: boolean
- ) {
+ ) => {
const el = (n2.el = n1.el) as HostElement
let { patchFlag, dynamicChildren } = n2
const oldProps = (n1 && n1.props) || EMPTY_OBJ
}
// The fast path for blocks.
- function patchBlockChildren(
+ const patchBlockChildren = (
oldChildren: HostVNode[],
newChildren: HostVNode[],
fallbackContainer: HostElement,
parentComponent: ComponentInternalInstance | null,
parentSuspense: HostSuspenseBoundary | null,
isSVG: boolean
- ) {
+ ) => {
for (let i = 0; i < newChildren.length; i++) {
const oldVNode = oldChildren[i]
const newVNode = newChildren[i]
}
}
- function patchProps(
+ const patchProps = (
el: HostElement,
vnode: HostVNode,
oldProps: Data,
parentComponent: ComponentInternalInstance | null,
parentSuspense: HostSuspenseBoundary | null,
isSVG: boolean
- ) {
+ ) => {
if (oldProps !== newProps) {
for (const key in newProps) {
if (isReservedProp(key)) continue
let devFragmentID = 0
- function processFragment(
+ const processFragment = (
n1: HostVNode | null,
n2: HostVNode,
container: HostElement,
parentSuspense: HostSuspenseBoundary | null,
isSVG: boolean,
optimized: boolean
- ) {
+ ) => {
const showID = __DEV__ && !__TEST__
const fragmentStartAnchor = (n2.el = n1
? n1.el
}
}
- function processPortal(
+ const processPortal = (
n1: HostVNode | null,
n2: HostVNode,
container: HostElement,
parentSuspense: HostSuspenseBoundary | null,
isSVG: boolean,
optimized: boolean
- ) {
+ ) => {
const targetSelector = n2.props && n2.props.target
const { patchFlag, shapeFlag, children } = n2
if (n1 == null) {
processCommentNode(n1, n2, container, anchor)
}
- function processComponent(
+ const processComponent = (
n1: HostVNode | null,
n2: HostVNode,
container: HostElement,
parentSuspense: HostSuspenseBoundary | null,
isSVG: boolean,
optimized: boolean
- ) {
+ ) => {
if (n1 == null) {
if (n2.shapeFlag & ShapeFlags.COMPONENT_KEPT_ALIVE) {
;(parentComponent!.sink as KeepAliveSink).activate(
}
}
- function mountComponent(
+ const mountComponent = (
initialVNode: HostVNode,
container: HostElement | null, // only null during hydration
anchor: HostNode | null,
parentComponent: ComponentInternalInstance | null,
parentSuspense: HostSuspenseBoundary | null,
isSVG: boolean
- ) {
+ ) => {
const instance: ComponentInternalInstance = (initialVNode.component = createComponentInstance(
initialVNode,
parentComponent
}
}
- function setupRenderEffect(
+ const setupRenderEffect = (
instance: ComponentInternalInstance,
initialVNode: HostVNode,
container: HostElement | null, // only null during hydration
anchor: HostNode | null,
parentSuspense: HostSuspenseBoundary | null,
isSVG: boolean
- ) {
+ ) => {
// create reactive effect for rendering
instance.update = effect(function componentEffect() {
if (!instance.isMounted) {
}, __DEV__ ? createDevEffectOptions(instance) : prodEffectOptions)
}
- function updateComponentPreRender(
+ const updateComponentPreRender = (
instance: ComponentInternalInstance,
nextVNode: HostVNode
- ) {
+ ) => {
nextVNode.component = instance
instance.vnode = nextVNode
instance.next = null
resolveSlots(instance, nextVNode.children)
}
- function patchChildren(
+ const patchChildren = (
n1: HostVNode | null,
n2: HostVNode,
container: HostElement,
parentSuspense: HostSuspenseBoundary | null,
isSVG: boolean,
optimized: boolean = false
- ) {
+ ) => {
const c1 = n1 && n1.children
const prevShapeFlag = n1 ? n1.shapeFlag : 0
const c2 = n2.children
}
}
- function patchUnkeyedChildren(
+ const patchUnkeyedChildren = (
c1: HostVNode[],
c2: HostVNodeChildren,
container: HostElement,
parentSuspense: HostSuspenseBoundary | null,
isSVG: boolean,
optimized: boolean
- ) {
+ ) => {
c1 = c1 || EMPTY_ARR
c2 = c2 || EMPTY_ARR
const oldLength = c1.length
}
// can be all-keyed or mixed
- function patchKeyedChildren(
+ const patchKeyedChildren = (
c1: HostVNode[],
c2: HostVNodeChildren,
container: HostElement,
parentSuspense: HostSuspenseBoundary | null,
isSVG: boolean,
optimized: boolean
- ) {
+ ) => {
let i = 0
const l2 = c2.length
let e1 = c1.length - 1 // prev ending index
}
}
- function move(
+ const move = (
vnode: HostVNode,
container: HostElement,
anchor: HostNode | null,
type: MoveType,
parentSuspense: HostSuspenseBoundary | null = null
- ) {
+ ) => {
if (vnode.shapeFlag & ShapeFlags.COMPONENT) {
move(vnode.component!.subTree, container, anchor, type)
return
}
}
- function unmount(
+ const unmount = (
vnode: HostVNode,
parentComponent: ComponentInternalInstance | null,
parentSuspense: HostSuspenseBoundary | null,
doRemove?: boolean
- ) {
+ ) => {
const { props, ref, children, dynamicChildren, shapeFlag } = vnode
// unset ref
}
}
- function remove(vnode: HostVNode) {
+ const remove = (vnode: HostVNode) => {
const { type, el, anchor, transition } = vnode
if (type === Fragment) {
removeFragment(el!, anchor!)
}
}
- function removeFragment(cur: HostNode, end: HostNode) {
+ const removeFragment = (cur: HostNode, end: HostNode) => {
// For fragments, directly remove all contained DOM nodes.
// (fragment child nodes cannot have transition)
let next
hostRemove(end)
}
- function unmountComponent(
+ const unmountComponent = (
instance: ComponentInternalInstance,
parentSuspense: HostSuspenseBoundary | null,
doRemove?: boolean
- ) {
+ ) => {
if (__HMR__ && instance.type.__hmrId != null) {
unregisterHMR(instance)
}
}
}
- function unmountChildren(
+ const unmountChildren = (
children: HostVNode[],
parentComponent: ComponentInternalInstance | null,
parentSuspense: HostSuspenseBoundary | null,
doRemove?: boolean,
start: number = 0
- ) {
+ ) => {
for (let i = start; i < children.length; i++) {
unmount(children[i], parentComponent, parentSuspense, doRemove)
}
}
- function getNextHostNode(vnode: HostVNode): HostNode | null {
+ const getNextHostNode = (vnode: HostVNode): HostNode | null => {
if (vnode.shapeFlag & ShapeFlags.COMPONENT) {
return getNextHostNode(vnode.component!.subTree)
}
return hostNextSibling((vnode.anchor || vnode.el)!)
}
- function setRef(
+ const setRef = (
ref: string | Function | Ref,
oldRef: string | Function | Ref | null,
parent: ComponentInternalInstance,
value: HostNode | ComponentPublicInstance | null
- ) {
+ ) => {
const refs = parent.refs === EMPTY_OBJ ? (parent.refs = {}) : parent.refs
const renderContext = toRaw(parent.renderContext)
container._vnode = vnode
}
+ const internals: RendererInternals<HostNode, HostElement> = {
+ patch,
+ unmount,
+ move,
+ next: getNextHostNode,
+ options
+ }
+
+ let hydrate: ReturnType<typeof createHydrationFunctions>[0] | undefined
+ let hydrateNode: ReturnType<typeof createHydrationFunctions>[1] | undefined
+ if (createHydrationFns) {
+ ;[hydrate, hydrateNode] = createHydrationFns(mountComponent, hostPatchProp)
+ }
+
return {
render,
hydrate,