]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
wip: vdom in vapor hmr reload
authorEvan You <evan@vuejs.org>
Tue, 4 Feb 2025 14:44:17 +0000 (22:44 +0800)
committerEvan You <evan@vuejs.org>
Tue, 4 Feb 2025 14:44:17 +0000 (22:44 +0800)
13 files changed:
packages/runtime-core/src/apiAsyncComponent.ts
packages/runtime-core/src/component.ts
packages/runtime-core/src/componentProps.ts
packages/runtime-core/src/componentPublicInstance.ts
packages/runtime-core/src/componentRenderUtils.ts
packages/runtime-core/src/components/KeepAlive.ts
packages/runtime-core/src/hmr.ts
packages/runtime-core/src/hydration.ts
packages/runtime-core/src/renderer.ts
packages/runtime-core/src/vnode.ts
packages/runtime-core/src/warning.ts
packages/runtime-dom/src/components/TransitionGroup.ts
packages/server-renderer/src/render.ts

index d7abb25fe1eae3cee1c94926b99d6ebdbcc0e69b..07e7fc67fef9c125dcceb4e3e8935d2b3e8bf0dc 100644 (file)
@@ -3,6 +3,7 @@ import {
   type ComponentInternalInstance,
   type ComponentOptions,
   type ConcreteComponent,
+  type GenericComponentInstance,
   currentInstance,
   isInSSRComponentSetup,
 } from './component'
@@ -39,7 +40,7 @@ export interface AsyncComponentOptions<T = any> {
   ) => any
 }
 
-export const isAsyncWrapper = (i: ComponentInternalInstance | VNode): boolean =>
+export const isAsyncWrapper = (i: GenericComponentInstance | VNode): boolean =>
   !!(i.type as ComponentOptions).__asyncLoader
 
 /*! #__NO_SIDE_EFFECTS__ */
@@ -206,10 +207,14 @@ export function defineAsyncComponent<
       load()
         .then(() => {
           loaded.value = true
-          if (instance.parent && isKeepAlive(instance.parent.vnode)) {
+          if (
+            instance.parent &&
+            instance.parent.vnode &&
+            isKeepAlive(instance.parent.vnode)
+          ) {
             // parent is keep-alive, force update so the loaded component's
             // name is taken into account
-            instance.parent.update()
+            ;(instance.parent as ComponentInternalInstance).update()
           }
         })
         .catch(err => {
index 06f6e51ea8009e60626736acc9132aff1a91c8c9..005e5dd3eeb4079de778764f3b07f150bee122a7 100644 (file)
@@ -504,6 +504,26 @@ export interface GenericComponentInstance {
    * @internal vapor only
    */
   hmrReload?: (newComp: any) => void
+
+  // these only exist on vdom instances
+  vnode?: VNode
+  subTree?: VNode
+
+  /**
+   * Custom Element instance (if component is created by defineCustomElement)
+   * @internal
+   */
+  ce?: ComponentCustomElementInterface
+  /**
+   * is custom element? (kept only for compatibility)
+   * @internal
+   */
+  isCE?: boolean
+  /**
+   * custom element specific HMR method
+   * @internal
+   */
+  ceReload?: (newStyles?: string[]) => void
 }
 
 /**
@@ -514,8 +534,8 @@ export interface ComponentInternalInstance extends GenericComponentInstance {
   vapor?: never
   uid: number
   type: ConcreteComponent
-  parent: ComponentInternalInstance | null
-  root: ComponentInternalInstance
+  parent: GenericComponentInstance | null
+  root: GenericComponentInstance
   appContext: AppContext
   /**
    * Vnode representing this component in its parent's vdom tree
@@ -589,21 +609,6 @@ export interface ComponentInternalInstance extends GenericComponentInstance {
    * @internal
    */
   inheritAttrs?: boolean
-  /**
-   * Custom Element instance (if component is created by defineCustomElement)
-   * @internal
-   */
-  ce?: ComponentCustomElementInterface
-  /**
-   * is custom element? (kept only for compatibility)
-   * @internal
-   */
-  isCE?: boolean
-  /**
-   * custom element specific HMR method
-   * @internal
-   */
-  ceReload?: (newStyles?: string[]) => void
 
   // the rest are only for stateful components ---------------------------------
   /**
@@ -1210,7 +1215,7 @@ export function expose(
 }
 
 export function getComponentPublicInstance(
-  instance: ComponentInternalInstance,
+  instance: GenericComponentInstance,
 ): ComponentPublicInstance | ComponentInternalInstance['exposed'] | null {
   if (instance.exposed) {
     return (
index c5ce317f7c19b0174110cb4bb68c5ce096b7ec69..d0fe97ff03dac3f4e7d98a62f7086193d7f4c88e 100644 (file)
@@ -232,7 +232,7 @@ export function initProps(
   instance.attrs = attrs
 }
 
-function isInHmrContext(instance: ComponentInternalInstance | null) {
+function isInHmrContext(instance: GenericComponentInstance | null) {
   while (instance) {
     if (instance.type.__hmrId) return true
     instance = instance.parent
index e9e7770ebd988ac2c8ac2b43979d5c9351916cf9..a43c99e2f45accdd137e689bd253f82f74890337 100644 (file)
@@ -2,6 +2,7 @@ import {
   type Component,
   type ComponentInternalInstance,
   type Data,
+  type GenericComponentInstance,
   getComponentPublicInstance,
   isStatefulComponent,
 } from './component'
@@ -355,10 +356,11 @@ export type PublicPropertiesMap = Record<
  * public $parent chains, skip functional ones and go to the parent instead.
  */
 const getPublicInstance = (
-  i: ComponentInternalInstance | null,
+  i: GenericComponentInstance | null,
 ): ComponentPublicInstance | ComponentInternalInstance['exposed'] | null => {
-  if (!i) return null
-  if (isStatefulComponent(i)) return getComponentPublicInstance(i)
+  if (!i || i.vapor) return null
+  if (isStatefulComponent(i as ComponentInternalInstance))
+    return getComponentPublicInstance(i)
   return getPublicInstance(i.parent)
 }
 
index 53e0b5a3e7706eb5126c367e22d3c973bd961726..a62b5cf4a82a37a4f726f750c6baa363df3ca9c2 100644 (file)
@@ -455,12 +455,12 @@ export function updateHOCHostEl(
   el: typeof vnode.el, // HostNode
 ): void {
   while (parent && !parent.vapor) {
-    const root = parent.subTree
+    const root = parent.subTree!
     if (root.suspense && root.suspense.activeBranch === vnode) {
       root.el = vnode.el
     }
     if (root === vnode) {
-      ;(vnode = parent.vnode).el = el
+      ;(vnode = parent.vnode!).el = el
       parent = parent.parent
     } else {
       break
index 2ceaaa9e602fe16d348d2fd907f7569fba62d23e..949de0bdd55f729b2586d3083de62e8f3092f0bf 100644 (file)
@@ -2,6 +2,7 @@ import {
   type ComponentInternalInstance,
   type ComponentOptions,
   type ConcreteComponent,
+  type GenericComponentInstance,
   type SetupContext,
   getComponentName,
   getCurrentInstance,
@@ -436,7 +437,7 @@ function registerKeepAliveHook(
     hook.__wdc ||
     (hook.__wdc = () => {
       // only fire the hook if the target instance is NOT in a deactivated branch.
-      let current: ComponentInternalInstance | null = target
+      let current: GenericComponentInstance | null = target
       while (current) {
         if (current.isDeactivated) {
           return
@@ -453,7 +454,7 @@ function registerKeepAliveHook(
   // arrays.
   if (target) {
     let current = target.parent
-    while (current && current.parent) {
+    while (current && current.parent && current.parent.vnode) {
       if (isKeepAlive(current.parent.vnode)) {
         injectToKeepAliveRoot(wrappedHook, type, target, current)
       }
@@ -466,7 +467,7 @@ function injectToKeepAliveRoot(
   hook: Function & { __weh?: Function },
   type: LifecycleHooks,
   target: ComponentInternalInstance,
-  keepAliveRoot: ComponentInternalInstance,
+  keepAliveRoot: GenericComponentInstance,
 ) {
   // injectHook wraps the original for error handling, so make sure to remove
   // the wrapped version.
index 42f671e8167768b9442212a450b87170e717c9aa..6fd6bb3f2eacfa7e7bf0d2e9be10a49b7bd1f636 100644 (file)
@@ -154,7 +154,12 @@ function reload(id: string, newComp: HMRComponent): void {
         // don't end up forcing the same parent to re-render multiple times.
         queueJob(() => {
           isHmrUpdating = true
-          instance.parent!.update()
+          const parent = instance.parent!
+          if (parent.vapor) {
+            parent.hmrRerender!()
+          } else {
+            ;(parent as ComponentInternalInstance).update()
+          }
           isHmrUpdating = false
           // #6930, #11248 avoid infinite recursion
           dirtyInstances.delete(instance)
index a94ff3568107e6c20d383eeb4e5e839012825ee2..652a84680d1367af7b198de54242d983afda5e77 100644 (file)
@@ -768,7 +768,7 @@ export function createHydrationFunctions(
       if (parent.vnode.el === oldNode) {
         parent.vnode.el = parent.subTree.el = newNode
       }
-      parent = parent.parent
+      parent = parent.parent as ComponentInternalInstance
     }
   }
 
@@ -945,7 +945,11 @@ function resolveCssVars(
     }
   }
   if (vnode === root && instance.parent) {
-    resolveCssVars(instance.parent, instance.vnode, expectedMap)
+    resolveCssVars(
+      instance.parent as ComponentInternalInstance,
+      instance.vnode,
+      expectedMap,
+    )
   }
 }
 
index fff68dd2c6407f18d76a4ef18353c72e98c0b727..08e6180818715de21fc5b3dd7c6f072d7da6e718 100644 (file)
@@ -19,6 +19,7 @@ import {
   type ComponentOptions,
   type ConcreteComponent,
   type Data,
+  type GenericComponentInstance,
   type LifecycleHook,
   createComponentInstance,
   getComponentPublicInstance,
@@ -749,7 +750,7 @@ function baseCreateRenderer(
     vnode: VNode,
     scopeId: string | null,
     slotScopeIds: string[] | null,
-    parentComponent: ComponentInternalInstance | null,
+    parentComponent: GenericComponentInstance | null,
   ) => {
     if (scopeId) {
       hostSetScopeId(el, scopeId)
@@ -774,7 +775,7 @@ function baseCreateRenderer(
         (isSuspense(subTree.type) &&
           (subTree.ssContent === vnode || subTree.ssFallback === vnode))
       ) {
-        const parentVNode = parentComponent!.vnode
+        const parentVNode = parentComponent!.vnode!
         setScopeId(
           el,
           parentVNode,
@@ -1382,8 +1383,8 @@ function baseCreateRenderer(
           }
         } else {
           // custom element style injection
-          if (root.ce) {
-            root.ce._injectChildStyle(type)
+          if ((root as ComponentInternalInstance).ce) {
+            ;(root as ComponentInternalInstance).ce!._injectChildStyle(type)
           }
 
           if (__DEV__) {
index 17efef80a6276bd9a17745ad411fe828e67a8818..2d476bd4af0e2c2b187b6410cf8dfc725e966845 100644 (file)
@@ -18,6 +18,7 @@ import {
   type ComponentInternalInstance,
   type ConcreteComponent,
   type Data,
+  type GenericComponentInstance,
   isClassComponent,
 } from './component'
 import type { RawSlots } from './componentSlots'
@@ -903,7 +904,7 @@ export function mergeProps(...args: (Data & VNodeProps)[]): Data {
 
 export function invokeVNodeHook(
   hook: VNodeHook,
-  instance: ComponentInternalInstance | null,
+  instance: GenericComponentInstance | null,
   vnode: VNode,
   prevVNode: VNode | null = null,
 ): void {
index c261bf602bd8b495ff23458dba69ee0a91c23b17..361a2734ba4da81cbd79373d7a89e9cbebd8fef8 100644 (file)
@@ -1,5 +1,4 @@
 import {
-  type ComponentInternalInstance,
   type Data,
   type GenericComponentInstance,
   formatComponentName,
@@ -106,9 +105,9 @@ export function getComponentTrace(): ComponentTraceStack {
       })
     }
     if (isVNode(currentCtx)) {
-      const parent: ComponentInternalInstance | null =
+      const parent: GenericComponentInstance | null =
         currentCtx.component && currentCtx.component.parent
-      currentCtx = parent && parent.vnode
+      currentCtx = (parent && parent.vnode) || parent
     } else {
       currentCtx = currentCtx.parent
     }
index 928e5d955f11415736bd6691ba79afbed251acb4..8400e71d6c020200cb7bdf3c6c13ef8dcaea59d5 100644 (file)
@@ -10,6 +10,7 @@ import {
   vtcKey,
 } from './Transition'
 import {
+  type ComponentInternalInstance,
   type ComponentOptions,
   DeprecationTypes,
   Fragment,
@@ -122,7 +123,7 @@ const TransitionGroupImpl: ComponentOptions = /*@__PURE__*/ decorate({
         !rawProps.tag &&
         compatUtils.checkCompatEnabled(
           DeprecationTypes.TRANSITION_GROUP_ROOT,
-          instance.parent,
+          instance.parent as ComponentInternalInstance,
         )
       ) {
         tag = 'span'
index f04080b9c3127d04024b7a18cdc499118ea55af9..221d3895e2288f80699d918f333d3631498825f2 100644 (file)
@@ -172,7 +172,7 @@ function renderComponentSubTree(
         if (parent && parent.subTree && parent.subTree === cur.vnode) {
           // parent is a non-SSR compiled component and is rendering this
           // component as root. inherit its scopeId if present.
-          cur = parent
+          cur = parent as ComponentInternalInstance
         } else {
           break
         }
@@ -314,7 +314,7 @@ function renderElementVNode(
     if (curVnode.scopeId) {
       openTag += ` ${curVnode.scopeId}`
     }
-    curParent = curParent.parent
+    curParent = curParent.parent as ComponentInternalInstance
   }
   if (slotScopeId) {
     openTag += ` ${slotScopeId}`