Evan You пре 1 година
родитељ
комит
4833c1c96e

+ 15 - 5
packages/runtime-core/src/component.ts

@@ -381,6 +381,17 @@ export interface GenericComponentInstance {
   // exposed properties via expose()
   exposed: Record<string, any> | 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<unknown>>
+  /**
+   * @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

+ 2 - 1
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 = []

+ 1 - 0
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'

+ 1 - 0
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) {

+ 25 - 9
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<string, any>
+  devtoolsRawSetupState?: any
+  hmrRerender?: () => void
   propsOptions?: NormalizedPropsOptions
   emitsOptions?: ObjectEmitsOptions | null
 

+ 21 - 0
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)
+}