wip: prepare hmr reload

This commit is contained in:
Evan You 2024-12-08 21:22:51 +08:00
parent 6f449346c9
commit bb0787b8d4
No known key found for this signature in database
GPG Key ID: 00E9AB7A6704CE0A
5 changed files with 86 additions and 29 deletions

View File

@ -488,6 +488,10 @@ export interface GenericComponentInstance {
* @internal vapor only
*/
hmrRerender?: () => void
/**
* @internal vapor only
*/
hmrReload?: () => void
}
/**

View File

@ -96,8 +96,7 @@ function rerender(id: string, newRender?: Function): void {
// this flag forces child components with slot content to update
isHmrUpdating = true
if (instance.vapor) {
// @ts-expect-error TODO
instance.hmrRerender()
instance.hmrRerender!()
} else {
const i = instance as ComponentInternalInstance
i.renderCache = []
@ -119,7 +118,9 @@ function reload(id: string, newComp: HMRComponent): void {
const instances = [...record.instances]
if (newComp.vapor) {
// TODO
for (const instance of instances) {
instance.hmrReload!()
}
} else {
for (const instance of instances as ComponentInternalInstance[]) {
const oldComp = normalizeClassComponent(instance.type as HMRComponent)

View File

@ -20,7 +20,7 @@ import {
} from '@vue/runtime-dom'
import { type Block, isBlock } from './block'
import { pauseTracking, proxyRefs, resetTracking } from '@vue/reactivity'
import { EMPTY_OBJ, isFunction, isString } from '@vue/shared'
import { EMPTY_OBJ, invokeArrayFns, isFunction, isString } from '@vue/shared'
import {
type RawProps,
getPropsProxyHandlers,
@ -40,8 +40,8 @@ import {
dynamicSlotsProxyHandlers,
getSlot,
} from './componentSlots'
import { insert } from './dom/node'
import { hmrRerender } from './hmr'
import { insert, remove } from './dom/node'
import { hmrReload, hmrRerender } from './hmr'
export { currentInstance } from '@vue/runtime-dom'
@ -148,6 +148,7 @@ export function createComponent(
// HMR
registerHMR(instance)
instance.hmrRerender = hmrRerender.bind(null, instance)
instance.hmrReload = hmrReload.bind(null, instance)
}
} else {
// in prod result can only be block
@ -202,6 +203,7 @@ export class VaporComponentInstance implements GenericComponentInstance {
uid: number
type: VaporComponent
parent: GenericComponentInstance | null
children: VaporComponentInstance[] // TODO handle vdom children
appContext: GenericAppContext
block: Block
@ -254,6 +256,7 @@ export class VaporComponentInstance implements GenericComponentInstance {
setupState?: Record<string, any>
devtoolsRawSetupState?: any
hmrRerender?: () => void
hmrReload?: () => void
propsOptions?: NormalizedPropsOptions
emitsOptions?: ObjectEmitsOptions | null
@ -266,19 +269,26 @@ export class VaporComponentInstance implements GenericComponentInstance {
this.uid = nextUid()
this.type = comp
this.parent = currentInstance // TODO proper parent source when inside vdom instance
this.appContext = currentInstance
? currentInstance.appContext
: emptyContext
this.children = []
if (currentInstance) {
if (isVaporComponent(currentInstance)) {
currentInstance.children.push(this)
}
this.appContext = currentInstance.appContext
this.provides = currentInstance.provides
this.ids = currentInstance.ids
} else {
this.appContext = emptyContext
this.provides = Object.create(this.appContext.provides)
this.ids = ['', 0, 0]
}
this.block = null! // to be set
this.scope = new EffectScope(true)
this.emit = emit.bind(null, this)
this.provides = currentInstance
? currentInstance.provides
: Object.create(this.appContext.provides)
this.refs = EMPTY_OBJ
this.ids = currentInstance ? currentInstance.ids : ['', 0, 0]
this.emitted = this.exposed = this.propsDefaults = this.suspense = null
this.isMounted =
this.isUnmounted =
@ -381,3 +391,35 @@ export function createComponentWithFallback(
return el
}
export function mountComponent(
instance: VaporComponentInstance,
parent: ParentNode,
anchor: Node | null | 0,
): void {
if (!instance.isMounted) {
if (instance.bm) invokeArrayFns(instance.bm)
insert(instance.block, parent, anchor)
// queuePostFlushCb(() => {
if (instance.m) invokeArrayFns(instance.m)
instance.isMounted = true
// })
} else {
insert(instance.block, parent, anchor)
}
}
export function unmountComponent(
instance: VaporComponentInstance,
parent: ParentNode,
): void {
if (instance.isMounted && !instance.isUnmounted) {
if (instance.bum) invokeArrayFns(instance.bum)
// TODO invoke unmount recursively for children
remove(instance.block, parent)
// queuePostFlushCb(() => {
if (instance.um) invokeArrayFns(instance.um)
instance.isUnmounted = true
// })
}
}

View File

@ -1,8 +1,12 @@
import { invokeArrayFns, isArray } from '@vue/shared'
import { isArray } from '@vue/shared'
import { renderEffect } from '../renderEffect'
import { setText } from './prop'
import { type Block, normalizeBlock } from '../block'
import { isVaporComponent } from '../component'
import type { Block } from '../block'
import {
isVaporComponent,
mountComponent,
unmountComponent,
} from '../component'
export function insert(
block: Block,
@ -12,14 +16,7 @@ export function insert(
if (block instanceof Node) {
parent.insertBefore(block, anchor === 0 ? parent.firstChild : anchor)
} else if (isVaporComponent(block)) {
if (!block.isMounted) {
if (block.bm) invokeArrayFns(block.bm)
insert(block.block, parent, anchor)
if (block.m) invokeArrayFns(block.m)
block.isMounted = true
} else {
insert(block.block, parent, anchor)
}
mountComponent(block, parent, anchor)
} else if (isArray(block)) {
for (let i = 0; i < block.length; i++) {
insert(block[i], parent, anchor)
@ -35,15 +32,23 @@ export function prepend(parent: ParentNode, ...blocks: Block[]): void {
for (const b of blocks) insert(b, parent, 0)
}
// TODO optimize
// TODO invoke unmount recursive
export function remove(block: Block, parent: ParentNode): void {
const nodes = normalizeBlock(block)
for (let i = 0; i < nodes.length; i++) {
parent.removeChild(nodes[i])
if (block instanceof Node) {
parent.removeChild(block)
} else if (isVaporComponent(block)) {
unmountComponent(block, parent)
} else if (isArray(block)) {
for (let i = 0; i < block.length; i++) {
remove(block[i], parent)
}
} else {
// fragment
remove(block.nodes, parent)
if (block.anchor) remove(block.anchor, parent)
}
}
// TODO optimize
export function createTextNode(values?: any[] | (() => any[])): Text {
// eslint-disable-next-line no-restricted-globals
const node = document.createTextNode('')

View File

@ -19,3 +19,8 @@ export function hmrRerender(instance: VaporComponentInstance): void {
popWarningContext()
insert(instance.block, parent, anchor)
}
export function hmrReload(instance: VaporComponentInstance): void {
// in parent block, find the corresponding block of this instance
// create new instance, replace
}