From: daiwei Date: Fri, 24 Oct 2025 07:10:10 +0000 (+0800) Subject: wip: enhance VaporElement with type parameters and pre-rendering support X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=da010a70358e2f524c22374a93f5f79100274805;p=thirdparty%2Fvuejs%2Fcore.git wip: enhance VaporElement with type parameters and pre-rendering support --- diff --git a/packages/runtime-dom/src/apiCustomElement.ts b/packages/runtime-dom/src/apiCustomElement.ts index b8e5811700..91ba8e6060 100644 --- a/packages/runtime-dom/src/apiCustomElement.ts +++ b/packages/runtime-dom/src/apiCustomElement.ts @@ -201,6 +201,8 @@ const BaseClass = ( type InnerComponentDef = ConcreteComponent & CustomElementOptions export abstract class VueElementBase< + E = Element, + C = Component, Def extends CustomElementOptions & { props?: any } = InnerComponentDef, > extends BaseClass @@ -218,7 +220,7 @@ export abstract class VueElementBase< /** * @internal */ - _root: Element | ShadowRoot + _root!: Element | ShadowRoot /** * @internal */ @@ -230,7 +232,7 @@ export abstract class VueElementBase< protected _def: Def protected _props: Record - protected _createApp: CreateAppFunction + protected _createApp: CreateAppFunction protected _connected = false protected _resolved = false protected _numberProps: Record | null = null @@ -249,29 +251,27 @@ export abstract class VueElementBase< protected _ob?: MutationObserver | null = null protected _slots?: Record + protected abstract _hasPreRendered(): boolean | undefined + protected abstract _mountComponent(def: Def): void + protected abstract _updateComponent(): void + protected abstract _unmountComponent(): void + constructor( /** * Component def - note this may be an AsyncWrapper, and this._def will * be overwritten by the inner component when resolved. */ def: Def, - props: Record = {}, - createAppFn: CreateAppFunction = createApp, + props: Record | undefined = {}, + createAppFn: CreateAppFunction, ) { super() this._def = def this._props = props this._createApp = createAppFn this._nonce = def.nonce - if (this.shadowRoot && createAppFn !== createApp) { - this._root = this.shadowRoot - } else { - if (__DEV__ && this.shadowRoot) { - warn( - `Custom element has pre-rendered declarative shadow root but is not ` + - `defined as hydratable. Use \`defineSSRCustomElement\`.`, - ) - } + + if (this._hasPreRendered()) { if (def.shadowRoot !== false) { this.attachShadow( extend({}, def.shadowRootOptions, { @@ -322,10 +322,6 @@ export abstract class VueElementBase< } } - protected abstract _mountComponent(def: Def): void - protected abstract _updateComponent(): void - protected abstract _unmountComponent(): void - protected _setParent( parent: VueElementBase | undefined = this._parent, ): void { @@ -643,7 +639,33 @@ export abstract class VueElementBase< } } -export class VueElement extends VueElementBase { +export class VueElement extends VueElementBase< + Element, + Component, + InnerComponentDef +> { + constructor( + def: InnerComponentDef, + props: Record | undefined = {}, + createAppFn: CreateAppFunction = createApp, + ) { + super(def, props, createAppFn) + } + + protected _hasPreRendered(): boolean | undefined { + if (this.shadowRoot && this._createApp !== createApp) { + this._root = this.shadowRoot + } else { + if (__DEV__ && this.shadowRoot) { + warn( + `Custom element has pre-rendered declarative shadow root but is not ` + + `defined as hydratable. Use \`defineSSRCustomElement\`.`, + ) + } + return true + } + } + protected _mountComponent(def: InnerComponentDef): void { if ((__DEV__ || __FEATURE_PROD_DEVTOOLS__) && !def.name) { // @ts-expect-error diff --git a/packages/runtime-vapor/src/apiDefineVaporCustomElement.ts b/packages/runtime-vapor/src/apiDefineVaporCustomElement.ts index bda741a0b7..fa443268ab 100644 --- a/packages/runtime-vapor/src/apiDefineVaporCustomElement.ts +++ b/packages/runtime-vapor/src/apiDefineVaporCustomElement.ts @@ -1,9 +1,10 @@ import { extend, isPlainObject } from '@vue/shared' -import { defineVaporComponent } from '.' +import { createVaporApp, defineVaporComponent } from '.' import { type CreateAppFunction, type CustomElementOptions, VueElementBase, + warn, } from '@vue/runtime-dom' import type { ObjectVaporComponent, VaporComponent } from './component' @@ -14,13 +15,13 @@ export type VaporElementConstructor

= { // TODO type inference /*@__NO_SIDE_EFFECTS__*/ -export function defineCustomElement( +export function defineVaporCustomElement( options: any, extraOptions?: Omit, /** * @internal */ - _createApp?: CreateAppFunction, + _createApp?: CreateAppFunction, ): VaporElementConstructor { let Comp = defineVaporComponent(options, extraOptions) if (isPlainObject(Comp)) Comp = extend({}, Comp, extraOptions) @@ -34,9 +35,43 @@ export function defineCustomElement( return VaporCustomElement } +/*@__NO_SIDE_EFFECTS__*/ +export const defineVaporSSRCustomElement = (( + options: any, + extraOptions?: Omit, +) => { + // @ts-expect-error + return defineVaporCustomElement(options, extraOptions, createVaporSSRApp) +}) as typeof defineVaporCustomElement + type VaporInnerComponentDef = VaporComponent & CustomElementOptions -export class VaporElement extends VueElementBase { +export class VaporElement extends VueElementBase< + ParentNode, + VaporComponent, + VaporInnerComponentDef +> { + constructor( + def: VaporInnerComponentDef, + props: Record | undefined = {}, + createAppFn: CreateAppFunction = createVaporApp, + ) { + super(def, props, createAppFn) + } + + protected _hasPreRendered(): boolean | undefined { + if (this.shadowRoot && this._createApp !== createVaporApp) { + this._root = this.shadowRoot + } else { + if (__DEV__ && this.shadowRoot) { + warn( + `Custom element has pre-rendered declarative shadow root but is not ` + + `defined as hydratable. Use \`defineVaporSSRCustomElement\`.`, + ) + } + return true + } + } protected _mountComponent(def: VaporInnerComponentDef): void { throw new Error('Method not implemented.') }