diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index f9dae3d21..3c69ebce1 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -381,6 +381,17 @@ export interface GenericComponentInstance { // exposed properties via expose() exposed: Record | null + /** + * setup related + * @internal + */ + setupState?: Data + /** + * devtools access to additional info + * @internal + */ + devtoolsRawSetupState?: any + // lifecycle isMounted: boolean isUnmounted: boolean @@ -473,6 +484,10 @@ export interface GenericComponentInstance { * @internal */ [LifecycleHooks.SERVER_PREFETCH]?: LifecycleHook<() => Promise> + /** + * @internal vapor only + */ + hmrRerender?: () => void } /** @@ -584,11 +599,6 @@ export interface ComponentInternalInstance extends GenericComponentInstance { * @internal */ setupState: Data - /** - * devtools access to additional info - * @internal - */ - devtoolsRawSetupState?: any // main proxy that serves as the public instance (`this`) proxy: ComponentPublicInstance | null diff --git a/packages/runtime-core/src/hmr.ts b/packages/runtime-core/src/hmr.ts index 643f8ffff..2846c0222 100644 --- a/packages/runtime-core/src/hmr.ts +++ b/packages/runtime-core/src/hmr.ts @@ -96,7 +96,8 @@ function rerender(id: string, newRender?: Function): void { // this flag forces child components with slot content to update isHmrUpdating = true if (instance.vapor) { - // TODO + // @ts-expect-error TODO + instance.hmrRerender() } else { const i = instance as ComponentInternalInstance i.renderCache = [] diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index eb5f44896..8aabcd3ac 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -508,3 +508,4 @@ export { type AppUnmountFn, } from './apiCreateApp' export { currentInstance, setCurrentInstance } from './componentCurrentInstance' +export { registerHMR, unregisterHMR } from './hmr' diff --git a/packages/runtime-vapor/src/block.ts b/packages/runtime-vapor/src/block.ts index 570f1037f..582ca187b 100644 --- a/packages/runtime-vapor/src/block.ts +++ b/packages/runtime-vapor/src/block.ts @@ -40,6 +40,7 @@ export class DynamicFragment extends Fragment { if (this.scope) { this.scope.off() parent && remove(this.nodes, parent) + // TODO lifecycle unmount } if (render) { diff --git a/packages/runtime-vapor/src/component.ts b/packages/runtime-vapor/src/component.ts index 488999a8c..69f4a7bb6 100644 --- a/packages/runtime-vapor/src/component.ts +++ b/packages/runtime-vapor/src/component.ts @@ -14,6 +14,7 @@ import { nextUid, popWarningContext, pushWarningContext, + registerHMR, setCurrentInstance, warn, } from '@vue/runtime-dom' @@ -40,6 +41,7 @@ import { getSlot, } from './componentSlots' import { insert } from './dom/node' +import { hmrRerender } from './hmr' export { currentInstance } from '@vue/runtime-dom' @@ -139,15 +141,13 @@ export function createComponent( ) instance.block = [] } else { - instance.setupState = setupResult - instance.block = component.render.call( - null, - proxyRefs(setupResult), - instance.props, - instance.emit, - instance.attrs, - instance.slots, - ) + instance.devtoolsRawSetupState = setupResult + instance.setupState = proxyRefs(setupResult) + devRender(instance) + + // HMR + registerHMR(instance) + instance.hmrRerender = hmrRerender.bind(null, instance) } } else { // in prod result can only be block @@ -177,6 +177,20 @@ export function createComponent( 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 = { app: null as any, config: {}, @@ -238,6 +252,8 @@ export class VaporComponentInstance implements GenericComponentInstance { // dev only setupState?: Record + devtoolsRawSetupState?: any + hmrRerender?: () => void propsOptions?: NormalizedPropsOptions emitsOptions?: ObjectEmitsOptions | null diff --git a/packages/runtime-vapor/src/hmr.ts b/packages/runtime-vapor/src/hmr.ts new file mode 100644 index 000000000..51b9fa224 --- /dev/null +++ b/packages/runtime-vapor/src/hmr.ts @@ -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) +}