mirror of https://github.com/vuejs/core.git
wip: fix teleport root component hmr reload
This commit is contained in:
parent
b6468562e6
commit
b474ce0a1e
|
@ -317,7 +317,7 @@ describe('renderer: VaporTeleport', () => {
|
||||||
expect(target.innerHTML).toBe('')
|
expect(target.innerHTML).toBe('')
|
||||||
})
|
})
|
||||||
|
|
||||||
test.todo('reload child + toggle disabled', async () => {
|
test('reload child + toggle disabled', async () => {
|
||||||
const target = document.createElement('div')
|
const target = document.createElement('div')
|
||||||
const root = document.createElement('div')
|
const root = document.createElement('div')
|
||||||
const childId = 'test3-child'
|
const childId = 'test3-child'
|
||||||
|
@ -410,8 +410,6 @@ describe('renderer: VaporTeleport', () => {
|
||||||
)
|
)
|
||||||
expect(target.innerHTML).toBe('')
|
expect(target.innerHTML).toBe('')
|
||||||
|
|
||||||
//bug: child reload not update teleport fragment's nodes
|
|
||||||
|
|
||||||
// toggle disabled
|
// toggle disabled
|
||||||
disabled.value = false
|
disabled.value = false
|
||||||
await nextTick()
|
await nextTick()
|
||||||
|
|
|
@ -25,6 +25,7 @@ export class VaporFragment {
|
||||||
anchor?: Node
|
anchor?: Node
|
||||||
insert?: (parent: ParentNode, anchor: Node | null) => void
|
insert?: (parent: ParentNode, anchor: Node | null) => void
|
||||||
remove?: (parent?: ParentNode) => void
|
remove?: (parent?: ParentNode) => void
|
||||||
|
getNodes?: () => Block
|
||||||
|
|
||||||
constructor(nodes: Block) {
|
constructor(nodes: Block) {
|
||||||
this.nodes = nodes
|
this.nodes = nodes
|
||||||
|
@ -184,8 +185,8 @@ export function normalizeBlock(block: Block): Node[] {
|
||||||
} else if (isVaporComponent(block)) {
|
} else if (isVaporComponent(block)) {
|
||||||
nodes.push(...normalizeBlock(block.block!))
|
nodes.push(...normalizeBlock(block.block!))
|
||||||
} else {
|
} else {
|
||||||
if ((block as any).getNodes) {
|
if (block.getNodes) {
|
||||||
nodes.push(...normalizeBlock((block as any).getNodes()))
|
nodes.push(...normalizeBlock(block.getNodes()))
|
||||||
} else {
|
} else {
|
||||||
nodes.push(...normalizeBlock(block.nodes))
|
nodes.push(...normalizeBlock(block.nodes))
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,11 @@ import {
|
||||||
import { hmrReload, hmrRerender } from './hmr'
|
import { hmrReload, hmrRerender } from './hmr'
|
||||||
import { isHydrating, locateHydrationNode } from './dom/hydration'
|
import { isHydrating, locateHydrationNode } from './dom/hydration'
|
||||||
import { insertionAnchor, insertionParent } from './insertionState'
|
import { insertionAnchor, insertionParent } from './insertionState'
|
||||||
import type { VaporTeleportImpl } from './components/Teleport'
|
import {
|
||||||
|
type VaporTeleportImpl,
|
||||||
|
instanceToTeleportMap,
|
||||||
|
teleportStack,
|
||||||
|
} from './components/Teleport'
|
||||||
|
|
||||||
export { currentInstance } from '@vue/runtime-dom'
|
export { currentInstance } from '@vue/runtime-dom'
|
||||||
|
|
||||||
|
@ -209,6 +213,11 @@ export function createComponent(
|
||||||
)
|
)
|
||||||
|
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
|
let teleport = teleportStack[teleportStack.length - 1]
|
||||||
|
if (teleport) {
|
||||||
|
instanceToTeleportMap.set(instance, teleport)
|
||||||
|
}
|
||||||
|
|
||||||
pushWarningContext(instance)
|
pushWarningContext(instance)
|
||||||
startMeasure(instance, `init`)
|
startMeasure(instance, `init`)
|
||||||
|
|
||||||
|
@ -296,7 +305,7 @@ export function createComponent(
|
||||||
onScopeDispose(() => unmountComponent(instance), true)
|
onScopeDispose(() => unmountComponent(instance), true)
|
||||||
|
|
||||||
if (!isHydrating && _insertionParent) {
|
if (!isHydrating && _insertionParent) {
|
||||||
insert(instance.block, _insertionParent, _insertionAnchor)
|
mountComponent(instance, _insertionParent, _insertionAnchor)
|
||||||
}
|
}
|
||||||
|
|
||||||
return instance
|
return instance
|
||||||
|
|
|
@ -15,12 +15,45 @@ import {
|
||||||
remove,
|
remove,
|
||||||
} from '../block'
|
} from '../block'
|
||||||
import { createComment, createTextNode, querySelector } from '../dom/node'
|
import { createComment, createTextNode, querySelector } from '../dom/node'
|
||||||
import type { LooseRawProps, LooseRawSlots } from '../component'
|
import type {
|
||||||
|
LooseRawProps,
|
||||||
|
LooseRawSlots,
|
||||||
|
VaporComponentInstance,
|
||||||
|
} from '../component'
|
||||||
import { rawPropsProxyHandlers } from '../componentProps'
|
import { rawPropsProxyHandlers } from '../componentProps'
|
||||||
import { renderEffect } from '../renderEffect'
|
import { renderEffect } from '../renderEffect'
|
||||||
import { extend } from '@vue/shared'
|
import { extend, isArray } from '@vue/shared'
|
||||||
import { EffectScope, pauseTracking, resetTracking } from '@vue/reactivity'
|
import { EffectScope, pauseTracking, resetTracking } from '@vue/reactivity'
|
||||||
|
|
||||||
|
export const teleportStack: TeleportFragment[] = []
|
||||||
|
export const instanceToTeleportMap: WeakMap<
|
||||||
|
VaporComponentInstance,
|
||||||
|
TeleportFragment
|
||||||
|
> = __DEV__ ? new WeakMap() : (null as any)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dev only.
|
||||||
|
* when the **root** child component updates, synchronously update
|
||||||
|
* the TeleportFragment's children and nodes.
|
||||||
|
*/
|
||||||
|
export function handleTeleportChildrenHmrReload(
|
||||||
|
instance: VaporComponentInstance,
|
||||||
|
newInstance: VaporComponentInstance,
|
||||||
|
): void {
|
||||||
|
const teleport = instanceToTeleportMap.get(instance)
|
||||||
|
if (teleport) {
|
||||||
|
instanceToTeleportMap.set(newInstance, teleport)
|
||||||
|
if (teleport.nodes === instance) {
|
||||||
|
teleport.children = teleport.nodes = newInstance
|
||||||
|
} else if (isArray(teleport.nodes)) {
|
||||||
|
const i = teleport.nodes.indexOf(instance)
|
||||||
|
if (i > -1) {
|
||||||
|
;(teleport.children as Block[])[i] = teleport.nodes[i] = newInstance
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const VaporTeleportImpl = {
|
export const VaporTeleportImpl = {
|
||||||
name: 'VaporTeleport',
|
name: 'VaporTeleport',
|
||||||
__isTeleport: true,
|
__isTeleport: true,
|
||||||
|
@ -34,11 +67,12 @@ export const VaporTeleportImpl = {
|
||||||
pauseTracking()
|
pauseTracking()
|
||||||
const scope = (frag.scope = new EffectScope())
|
const scope = (frag.scope = new EffectScope())
|
||||||
scope!.run(() => {
|
scope!.run(() => {
|
||||||
let children: Block
|
|
||||||
renderEffect(() => {
|
renderEffect(() => {
|
||||||
|
teleportStack.push(frag)
|
||||||
frag.updateChildren(
|
frag.updateChildren(
|
||||||
(children = slots.default && (slots.default as BlockFn)()),
|
(frag.children = slots.default && (slots.default as BlockFn)()),
|
||||||
)
|
)
|
||||||
|
teleportStack.pop()
|
||||||
})
|
})
|
||||||
|
|
||||||
renderEffect(() => {
|
renderEffect(() => {
|
||||||
|
@ -48,15 +82,17 @@ export const VaporTeleportImpl = {
|
||||||
{},
|
{},
|
||||||
new Proxy(props, rawPropsProxyHandlers) as any as TeleportProps,
|
new Proxy(props, rawPropsProxyHandlers) as any as TeleportProps,
|
||||||
),
|
),
|
||||||
children!,
|
frag.children!,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
resetTracking()
|
resetTracking()
|
||||||
|
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
// TODO
|
// used in normalizeBlock to get the nodes of a TeleportFragment
|
||||||
;(frag as any).getNodes = () => {
|
// during hmr update. return empty array if the teleport content
|
||||||
|
// is mounted into the target container.
|
||||||
|
frag.getNodes = () => {
|
||||||
return frag.parent !== frag.currentParent ? [] : frag.nodes
|
return frag.parent !== frag.currentParent ? [] : frag.nodes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,6 +104,7 @@ export const VaporTeleportImpl = {
|
||||||
class TeleportFragment extends VaporFragment {
|
class TeleportFragment extends VaporFragment {
|
||||||
anchor: Node
|
anchor: Node
|
||||||
scope: EffectScope | undefined
|
scope: EffectScope | undefined
|
||||||
|
children: Block | undefined
|
||||||
|
|
||||||
private targetStart?: Node
|
private targetStart?: Node
|
||||||
private mainAnchor?: Node
|
private mainAnchor?: Node
|
||||||
|
@ -178,7 +215,7 @@ class TeleportFragment extends VaporFragment {
|
||||||
// remove nodes
|
// remove nodes
|
||||||
if (this.nodes) {
|
if (this.nodes) {
|
||||||
remove(this.nodes, this.currentParent)
|
remove(this.nodes, this.currentParent)
|
||||||
this.nodes = []
|
this.children = this.nodes = []
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove anchors
|
// remove anchors
|
||||||
|
|
|
@ -13,6 +13,7 @@ import {
|
||||||
mountComponent,
|
mountComponent,
|
||||||
unmountComponent,
|
unmountComponent,
|
||||||
} from './component'
|
} from './component'
|
||||||
|
import { handleTeleportChildrenHmrReload } from './components/Teleport'
|
||||||
|
|
||||||
export function hmrRerender(instance: VaporComponentInstance): void {
|
export function hmrRerender(instance: VaporComponentInstance): void {
|
||||||
const normalized = normalizeBlock(instance.block)
|
const normalized = normalizeBlock(instance.block)
|
||||||
|
@ -54,5 +55,5 @@ export function hmrReload(
|
||||||
)
|
)
|
||||||
simpleSetCurrentInstance(prev, instance.parent)
|
simpleSetCurrentInstance(prev, instance.parent)
|
||||||
mountComponent(newInstance, parent, anchor)
|
mountComponent(newInstance, parent, anchor)
|
||||||
instance.block = newInstance.block
|
handleTeleportChildrenHmrReload(instance, newInstance)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue