wip: vapor hmr rerender

This commit is contained in:
Evan You 2024-12-08 17:20:34 +08:00
parent 6c4018652b
commit 4833c1c96e
No known key found for this signature in database
GPG Key ID: 00E9AB7A6704CE0A
6 changed files with 65 additions and 15 deletions

View File

@ -381,6 +381,17 @@ export interface GenericComponentInstance {
// exposed properties via expose() // exposed properties via expose()
exposed: Record<string, any> | null exposed: Record<string, any> | null
/**
* setup related
* @internal
*/
setupState?: Data
/**
* devtools access to additional info
* @internal
*/
devtoolsRawSetupState?: any
// lifecycle // lifecycle
isMounted: boolean isMounted: boolean
isUnmounted: boolean isUnmounted: boolean
@ -473,6 +484,10 @@ export interface GenericComponentInstance {
* @internal * @internal
*/ */
[LifecycleHooks.SERVER_PREFETCH]?: LifecycleHook<() => Promise<unknown>> [LifecycleHooks.SERVER_PREFETCH]?: LifecycleHook<() => Promise<unknown>>
/**
* @internal vapor only
*/
hmrRerender?: () => void
} }
/** /**
@ -584,11 +599,6 @@ export interface ComponentInternalInstance extends GenericComponentInstance {
* @internal * @internal
*/ */
setupState: Data setupState: Data
/**
* devtools access to additional info
* @internal
*/
devtoolsRawSetupState?: any
// main proxy that serves as the public instance (`this`) // main proxy that serves as the public instance (`this`)
proxy: ComponentPublicInstance | null proxy: ComponentPublicInstance | null

View File

@ -96,7 +96,8 @@ function rerender(id: string, newRender?: Function): void {
// this flag forces child components with slot content to update // this flag forces child components with slot content to update
isHmrUpdating = true isHmrUpdating = true
if (instance.vapor) { if (instance.vapor) {
// TODO // @ts-expect-error TODO
instance.hmrRerender()
} else { } else {
const i = instance as ComponentInternalInstance const i = instance as ComponentInternalInstance
i.renderCache = [] i.renderCache = []

View File

@ -508,3 +508,4 @@ export {
type AppUnmountFn, type AppUnmountFn,
} from './apiCreateApp' } from './apiCreateApp'
export { currentInstance, setCurrentInstance } from './componentCurrentInstance' export { currentInstance, setCurrentInstance } from './componentCurrentInstance'
export { registerHMR, unregisterHMR } from './hmr'

View File

@ -40,6 +40,7 @@ export class DynamicFragment extends Fragment {
if (this.scope) { if (this.scope) {
this.scope.off() this.scope.off()
parent && remove(this.nodes, parent) parent && remove(this.nodes, parent)
// TODO lifecycle unmount
} }
if (render) { if (render) {

View File

@ -14,6 +14,7 @@ import {
nextUid, nextUid,
popWarningContext, popWarningContext,
pushWarningContext, pushWarningContext,
registerHMR,
setCurrentInstance, setCurrentInstance,
warn, warn,
} from '@vue/runtime-dom' } from '@vue/runtime-dom'
@ -40,6 +41,7 @@ import {
getSlot, getSlot,
} from './componentSlots' } from './componentSlots'
import { insert } from './dom/node' import { insert } from './dom/node'
import { hmrRerender } from './hmr'
export { currentInstance } from '@vue/runtime-dom' export { currentInstance } from '@vue/runtime-dom'
@ -139,15 +141,13 @@ export function createComponent(
) )
instance.block = [] instance.block = []
} else { } else {
instance.setupState = setupResult instance.devtoolsRawSetupState = setupResult
instance.block = component.render.call( instance.setupState = proxyRefs(setupResult)
null, devRender(instance)
proxyRefs(setupResult),
instance.props, // HMR
instance.emit, registerHMR(instance)
instance.attrs, instance.hmrRerender = hmrRerender.bind(null, instance)
instance.slots,
)
} }
} else { } else {
// in prod result can only be block // in prod result can only be block
@ -177,6 +177,20 @@ export function createComponent(
return instance return instance
} }
/**
* dev only
*/
export function devRender(instance: VaporComponentInstance): void {
instance.block = instance.type.render!.call(
null,
instance.setupState,
instance.props,
instance.emit,
instance.attrs,
instance.slots,
)
}
const emptyContext: GenericAppContext = { const emptyContext: GenericAppContext = {
app: null as any, app: null as any,
config: {}, config: {},
@ -238,6 +252,8 @@ export class VaporComponentInstance implements GenericComponentInstance {
// dev only // dev only
setupState?: Record<string, any> setupState?: Record<string, any>
devtoolsRawSetupState?: any
hmrRerender?: () => void
propsOptions?: NormalizedPropsOptions propsOptions?: NormalizedPropsOptions
emitsOptions?: ObjectEmitsOptions | null emitsOptions?: ObjectEmitsOptions | null

View File

@ -0,0 +1,21 @@
import {
popWarningContext,
pushWarningContext,
setCurrentInstance,
} from '@vue/runtime-core'
import { normalizeBlock } from './block'
import { type VaporComponentInstance, devRender } from './component'
import { insert, remove } from './dom/node'
export function hmrRerender(instance: VaporComponentInstance): void {
const normalized = normalizeBlock(instance.block)
const parent = normalized[0].parentNode!
const anchor = normalized[normalized.length - 1].nextSibling
remove(instance.block, parent)
const reset = setCurrentInstance(instance)
pushWarningContext(instance)
devRender(instance)
reset()
popWarningContext()
insert(instance.block, parent, anchor)
}