]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
wip: prepare hmr reload
authorEvan You <evan@vuejs.org>
Sun, 8 Dec 2024 13:22:51 +0000 (21:22 +0800)
committerEvan You <evan@vuejs.org>
Sun, 8 Dec 2024 13:22:51 +0000 (21:22 +0800)
packages/runtime-core/src/component.ts
packages/runtime-core/src/hmr.ts
packages/runtime-vapor/src/component.ts
packages/runtime-vapor/src/dom/node.ts
packages/runtime-vapor/src/hmr.ts

index 3c69ebce1f775a6b25b9d3bb3462ca5b5d5301a6..8a8129ffd38e141b70b8893fcdc065cb33ed5967 100644 (file)
@@ -488,6 +488,10 @@ export interface GenericComponentInstance {
    * @internal vapor only
    */
   hmrRerender?: () => void
+  /**
+   * @internal vapor only
+   */
+  hmrReload?: () => void
 }
 
 /**
index 2846c02228e1abcfdfc95f8d9be93c75a01cbcba..b2c52ab3effede57bf893a0223ff6a19cf6dcbae 100644 (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)
index 69f4a7bb6b86fc93821d54533a2c5b9384e60c4c..74e1f812773dcf20607ba8ee4e15e46c89b83292 100644 (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
+    // })
+  }
+}
index 246fdf8e30dce83be12f997d71565ee1adfb1a2d..e54966d83932f6a819f5d42104ce609683821b74 100644 (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('')
index 51b9fa224cdf287bca06216c814503c0abd4f99a..1cdfda3fc4223888cc5d319c651c56573b004092 100644 (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
+}