wip(runtime): support multi-element static vnode in renderer

This commit is contained in:
Evan You
2020-05-15 15:12:26 -04:00
parent cb9444807e
commit dbf627f136
3 changed files with 105 additions and 27 deletions

View File

@@ -116,8 +116,7 @@ export interface RendererOptions<
parent: HostElement,
anchor: HostNode | null,
isSVG: boolean
): HostElement
setStaticContent?(node: HostElement, content: string): void
): HostElement[]
}
// Renderer Node can technically be any object in the context of core renderer
@@ -333,8 +332,7 @@ function baseCreateRenderer(
nextSibling: hostNextSibling,
setScopeId: hostSetScopeId = NOOP,
cloneNode: hostCloneNode,
insertStaticContent: hostInsertStaticContent,
setStaticContent: hostSetStaticContent
insertStaticContent: hostInsertStaticContent
} = options
// Note: functions inside this closure should use `const xxx = () => {}`
@@ -373,11 +371,7 @@ function baseCreateRenderer(
if (n1 == null) {
mountStaticNode(n2, container, anchor, isSVG)
} else if (__DEV__) {
// static nodes are only patched during dev for HMR
n2.el = n1.el
if (n2.children !== n1.children) {
hostSetStaticContent!(n2.el!, n2.children as string)
}
patchStaticNode(n1, n2, container, isSVG)
}
break
case Fragment:
@@ -492,11 +486,19 @@ function baseCreateRenderer(
isSVG: boolean
) => {
if (n2.el && hostCloneNode !== undefined) {
hostInsert(hostCloneNode(n2.el), container, anchor)
// static node was already mounted (and reused), or adopted
// server-rendered node during hydration (in this case its children can be
// stripped by SSR optimizations). Clone the dom nodes instead.
let cur: RendererElement | null = n2.el
while (cur && cur !== n2.anchor) {
hostInsert(hostCloneNode(cur), container, anchor)
cur = hostNextSibling(cur)
}
hostInsert(hostCloneNode(n2.anchor!), container, anchor)
} else {
// static nodes are only present when used with compiler-dom/runtime-dom
// which guarantees presence of hostInsertStaticContent.
n2.el = hostInsertStaticContent!(
;[n2.el, n2.anchor] = hostInsertStaticContent!(
n2.children as string,
container,
anchor,
@@ -505,6 +507,64 @@ function baseCreateRenderer(
}
}
/**
* Dev / HMR only
*/
const patchStaticNode = (
n1: VNode,
n2: VNode,
container: RendererElement,
isSVG: boolean
) => {
// static nodes are only patched during dev for HMR
if (n2.children !== n1.children) {
const anchor = hostNextSibling(n1.anchor!)
// remove existing
removeStaticNode(n1)
// insert new
;[n2.el, n2.anchor] = hostInsertStaticContent!(
n2.children as string,
container,
anchor,
isSVG
)
} else {
n2.el = n1.el
n2.anchor = n1.anchor
}
}
/**
* Dev / HMR only
*/
const moveStaticNode = (
vnode: VNode,
container: RendererElement,
anchor: RendererNode | null
) => {
let cur = vnode.el
const end = vnode.anchor!
while (cur && cur !== end) {
const next = hostNextSibling(cur)
hostInsert(cur, container, anchor)
cur = next
}
hostInsert(end, container, anchor)
}
/**
* Dev / HMR only
*/
const removeStaticNode = (vnode: VNode) => {
let cur = vnode.el
while (cur && cur !== vnode.anchor) {
const next = hostNextSibling(cur)
hostRemove(cur)
cur = next
}
hostRemove(vnode.anchor!)
}
const processElement = (
n1: VNode | null,
n2: VNode,
@@ -1456,7 +1516,7 @@ function baseCreateRenderer(
n1,
n2,
container,
parentAnchor,
null,
parentComponent,
parentSuspense,
isSVG,
@@ -1481,7 +1541,7 @@ function baseCreateRenderer(
n1,
n2,
container,
parentAnchor,
null,
parentComponent,
parentSuspense,
isSVG,
@@ -1692,6 +1752,12 @@ function baseCreateRenderer(
return
}
// static node move can only happen when force updating HMR
if (__DEV__ && type === Static) {
moveStaticNode(vnode, container, anchor)
return
}
// single nodes
const needTransition =
moveType !== MoveType.REORDER &&
@@ -1808,6 +1874,11 @@ function baseCreateRenderer(
return
}
if (__DEV__ && type === Static) {
removeStaticNode(vnode)
return
}
const performRemove = () => {
hostRemove(el!)
if (transition && !transition.persisted && transition.afterLeave) {