]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
wip: save
authordaiwei <daiwei521@126.com>
Fri, 24 Oct 2025 09:13:11 +0000 (17:13 +0800)
committerdaiwei <daiwei521@126.com>
Fri, 24 Oct 2025 09:13:11 +0000 (17:13 +0800)
packages/runtime-core/src/apiCreateApp.ts
packages/runtime-dom/src/apiCustomElement.ts
packages/runtime-vapor/src/apiCreateApp.ts
packages/runtime-vapor/src/apiDefineVaporCustomElement.ts
packages/runtime-vapor/src/index.ts

index f651d76d79922d09bcc7fe1b73b77f8bf90db2a0..e3a63bf846d486d361b9283a835604261fb3e18e 100644 (file)
@@ -111,6 +111,11 @@ export interface App<HostElement = any> {
    */
   _ceVNode?: VNode
 
+  /**
+   * @internal vapor custom element instance
+   */
+  _ceComponent?: GenericComponentInstance | null
+
   /**
    * v2 compat only
    */
index 91ba8e606021503ef175e4c125816301ba5dd38e..61c3d7c4413d128fa9d057bf5e76dc357d57f6d3 100644 (file)
@@ -252,9 +252,9 @@ export abstract class VueElementBase<
   protected _slots?: Record<string, Node[]>
 
   protected abstract _hasPreRendered(): boolean | undefined
-  protected abstract _mountComponent(def: Def): void
-  protected abstract _updateComponent(): void
-  protected abstract _unmountComponent(): void
+  protected abstract _mount(def: Def): void
+  protected abstract _update(): void
+  protected abstract _unmount(): void
 
   constructor(
     /**
@@ -352,7 +352,7 @@ export abstract class VueElementBase<
           this._ob.disconnect()
           this._ob = null
         }
-        this._unmountComponent()
+        this._unmount()
         if (this._teleportTargets) {
           this._teleportTargets.clear()
           this._teleportTargets = undefined
@@ -436,6 +436,45 @@ export abstract class VueElementBase<
     }
   }
 
+  private _mountComponent(def: Def): void {
+    this._mount(def)
+    this._processExposed()
+  }
+
+  protected _processExposed(): void {
+    const exposed = this._instance && this._instance.exposed
+    if (!exposed) return
+    for (const key in exposed) {
+      if (!hasOwn(this, key)) {
+        Object.defineProperty(this, key, {
+          get: () => unref(exposed[key]),
+        })
+      } else if (__DEV__) {
+        warn(`Exposed property "${key}" already exists on custom element.`)
+      }
+    }
+  }
+
+  protected _processEmit(): void {
+    const dispatch = (event: string, args: any[]) => {
+      this.dispatchEvent(
+        new CustomEvent(
+          event,
+          isPlainObject(args[0])
+            ? extend({ detail: args }, args[0])
+            : { detail: args },
+        ),
+      )
+    }
+
+    this._instance!.emit = (event: string, ...args: any[]) => {
+      dispatch(event, args)
+      if (hyphenate(event) !== event) {
+        dispatch(hyphenate(event), args)
+      }
+    }
+  }
+
   private _resolveProps(def: Def): void {
     const { props } = def
     const declaredPropKeys = isArray(props) ? props : Object.keys(props || {})
@@ -498,7 +537,7 @@ export abstract class VueElementBase<
         }
       }
       if (shouldUpdate && this._instance) {
-        this._updateComponent()
+        this._update()
       }
       // reflect
       if (shouldReflect) {
@@ -666,7 +705,7 @@ export class VueElement extends VueElementBase<
     }
   }
 
-  protected _mountComponent(def: InnerComponentDef): void {
+  protected _mount(def: InnerComponentDef): void {
     if ((__DEV__ || __FEATURE_PROD_DEVTOOLS__) && !def.name) {
       // @ts-expect-error
       def.name = 'VueElement'
@@ -678,28 +717,16 @@ export class VueElement extends VueElementBase<
     }
     this._app._ceVNode = this._createVNode()
     this._app.mount(this._root)
-
-    const exposed = this._instance && this._instance.exposed
-    if (!exposed) return
-    for (const key in exposed) {
-      if (!hasOwn(this, key)) {
-        Object.defineProperty(this, key, {
-          get: () => unref(exposed[key]),
-        })
-      } else if (__DEV__) {
-        warn(`Exposed property "${key}" already exists on custom element.`)
-      }
-    }
   }
 
-  protected _updateComponent(): void {
+  protected _update(): void {
     if (!this._app) return
     const vnode = this._createVNode()
     vnode.appContext = this._app._context
     render(vnode, this._root)
   }
 
-  protected _unmountComponent(): void {
+  protected _unmount(): void {
     if (this._app) {
       this._app.unmount()
     }
@@ -729,28 +756,11 @@ export class VueElement extends VueElementBase<
             }
             this._applyStyles(newStyles)
             this._instance = null
-            this._updateComponent()
-          }
-        }
-
-        const dispatch = (event: string, args: any[]) => {
-          this.dispatchEvent(
-            new CustomEvent(
-              event,
-              isPlainObject(args[0])
-                ? extend({ detail: args }, args[0])
-                : { detail: args },
-            ),
-          )
-        }
-
-        instance.emit = (event: string, ...args: any[]) => {
-          dispatch(event, args)
-          if (hyphenate(event) !== event) {
-            dispatch(hyphenate(event), args)
+            this._update()
           }
         }
 
+        this._processEmit()
         this._setParent()
       }
     }
index 89fc6179ee04a96ce20d1f5dae172ea7b4d1a341..a50c12e60e79fabf81beb859223528a6e5248271 100644 (file)
@@ -36,14 +36,16 @@ const mountApp: AppMountFn<ParentNode> = (app, container) => {
     container.textContent = ''
   }
 
-  const instance = createComponent(
-    app._component,
-    app._props as RawProps,
-    null,
-    false,
-    false,
-    app._context,
-  )
+  const instance =
+    (app._ceComponent as VaporComponentInstance) ||
+    createComponent(
+      app._component,
+      app._props as RawProps,
+      null,
+      false,
+      false,
+      app._context,
+    )
   mountComponent(instance, container)
   flushOnAppMount()
 
@@ -57,14 +59,16 @@ const hydrateApp: AppMountFn<ParentNode> = (app, container) => {
 
   let instance: VaporComponentInstance
   withHydration(container, () => {
-    instance = createComponent(
-      app._component,
-      app._props as RawProps,
-      null,
-      false,
-      false,
-      app._context,
-    )
+    instance =
+      (app._ceComponent as VaporComponentInstance) ||
+      createComponent(
+        app._component,
+        app._props as RawProps,
+        null,
+        false,
+        false,
+        app._context,
+      )
     mountComponent(instance, container)
     flushOnAppMount()
   })
index fa443268ab029baeffc60931d43c322d7d40548f..8cc1782c444a3ae5cfde05b5306eca5cd86f8b15 100644 (file)
@@ -1,12 +1,18 @@
 import { extend, isPlainObject } from '@vue/shared'
-import { createVaporApp, defineVaporComponent } from '.'
+import { createComponent, createVaporApp, defineVaporComponent } from '.'
 import {
   type CreateAppFunction,
   type CustomElementOptions,
   VueElementBase,
   warn,
 } from '@vue/runtime-dom'
-import type { ObjectVaporComponent, VaporComponent } from './component'
+import {
+  type ObjectVaporComponent,
+  type VaporComponent,
+  type VaporComponentInstance,
+  mountComponent,
+  unmountComponent,
+} from './component'
 
 export type VaporElementConstructor<P = {}> = {
   new (initialProps?: Record<string, any>): VaporElement & P
@@ -72,13 +78,58 @@ export class VaporElement extends VueElementBase<
       return true
     }
   }
-  protected _mountComponent(def: VaporInnerComponentDef): void {
-    throw new Error('Method not implemented.')
+  protected _mount(def: VaporInnerComponentDef): void {
+    if ((__DEV__ || __FEATURE_PROD_DEVTOOLS__) && !def.name) {
+      def.name = 'VaporElement'
+    }
+
+    this._app = this._createApp(this._def)
+    this._inheritParentContext()
+    if (this._def.configureApp) {
+      this._def.configureApp(this._app)
+    }
+
+    this._app._ceComponent = this._createComponent()
+    this._app!.mount(this._root)
+  }
+
+  protected _update(): void {
+    if (!this._app) return
+    unmountComponent(this._instance! as VaporComponentInstance, this._root)
+    const instance = this._createComponent()
+    instance.appContext = this._app!._context
+    mountComponent(this._instance! as VaporComponentInstance, this._root)
   }
-  protected _updateComponent(): void {
-    throw new Error('Method not implemented.')
+
+  protected _unmount(): void {
+    this._app!.unmount()
+    this._app = this._instance = null
   }
-  protected _unmountComponent(): void {
-    throw new Error('Method not implemented.')
+
+  private _createComponent() {
+    this._instance = createComponent(this._def, this._props)
+    if (!this.shadowRoot) {
+      this._instance!.m = this._instance!.u = [this._renderSlots.bind(this)]
+    }
+
+    this._instance.ce = this
+    this._instance.isCE = true
+
+    if (__DEV__) {
+      this._instance.ceReload = newStyles => {
+        if (this._styles) {
+          this._styles.forEach(s => this._root.removeChild(s))
+          this._styles.length = 0
+        }
+        this._applyStyles(newStyles)
+        this._instance = null
+        this._update()
+      }
+    }
+
+    this._processEmit()
+    this._setParent()
+
+    return this._instance
   }
 }
index 0d718747d243abfb4b95a7d9e0cffc019df3cfa4..d8fbbf0e97c8f40a298a7d73a2124d3426a7edd6 100644 (file)
@@ -6,6 +6,10 @@ export { vaporInteropPlugin } from './vdomInterop'
 export type { VaporDirective } from './directives/custom'
 export { VaporTeleportImpl as VaporTeleport } from './components/Teleport'
 export { VaporKeepAliveImpl as VaporKeepAlive } from './components/KeepAlive'
+export {
+  defineVaporCustomElement,
+  defineVaporSSRCustomElement,
+} from './apiDefineVaporCustomElement'
 
 // compiler-use only
 export { insert, prepend, remove } from './block'