1
1
import {
2
+ type App ,
2
3
type Component ,
3
4
type ComponentCustomElementInterface ,
4
5
type ComponentInjectOptions ,
@@ -10,6 +11,7 @@ import {
10
11
type ComponentProvideOptions ,
11
12
type ComputedOptions ,
12
13
type ConcreteComponent ,
14
+ type CreateAppFunction ,
13
15
type CreateComponentPublicInstanceWithMixins ,
14
16
type DefineComponent ,
15
17
type Directive ,
@@ -18,7 +20,6 @@ import {
18
20
type ExtractPropTypes ,
19
21
type MethodOptions ,
20
22
type RenderFunction ,
21
- type RootHydrateFunction ,
22
23
type SetupContext ,
23
24
type SlotsType ,
24
25
type VNode ,
@@ -39,7 +40,7 @@ import {
39
40
isPlainObject ,
40
41
toNumber ,
41
42
} from '@vue/shared'
42
- import { hydrate , render } from '.'
43
+ import { createApp , createSSRApp , render } from '.'
43
44
44
45
export type VueElementConstructor < P = { } > = {
45
46
new ( initialProps ?: Record < string , any > ) : VueElement & P
@@ -49,6 +50,7 @@ export interface CustomElementOptions {
49
50
styles ?: string [ ]
50
51
shadowRoot ?: boolean
51
52
nonce ?: string
53
+ configureApp ?: ( app : App ) => void
52
54
}
53
55
54
56
// defineCustomElement provides the same type inference as defineComponent
@@ -165,14 +167,14 @@ export function defineCustomElement(
165
167
/**
166
168
* @internal
167
169
*/
168
- hydrate ?: RootHydrateFunction ,
170
+ _createApp ?: CreateAppFunction < Element > ,
169
171
) : VueElementConstructor {
170
172
const Comp = defineComponent ( options , extraOptions ) as any
171
173
if ( isPlainObject ( Comp ) ) extend ( Comp , extraOptions )
172
174
class VueCustomElement extends VueElement {
173
175
static def = Comp
174
176
constructor ( initialProps ?: Record < string , any > ) {
175
- super ( Comp , initialProps , hydrate )
177
+ super ( Comp , initialProps , _createApp )
176
178
}
177
179
}
178
180
@@ -185,7 +187,7 @@ export const defineSSRCustomElement = ((
185
187
extraOptions ?: ComponentOptions ,
186
188
) => {
187
189
// @ts -expect-error
188
- return defineCustomElement ( options , extraOptions , hydrate )
190
+ return defineCustomElement ( options , extraOptions , createSSRApp )
189
191
} ) as typeof defineCustomElement
190
192
191
193
const BaseClass = (
@@ -202,6 +204,14 @@ export class VueElement
202
204
* @internal
203
205
*/
204
206
_instance : ComponentInternalInstance | null = null
207
+ /**
208
+ * @internal
209
+ */
210
+ _app : App | null = null
211
+ /**
212
+ * @internal
213
+ */
214
+ _nonce = this . _def . nonce
205
215
206
216
private _connected = false
207
217
private _resolved = false
@@ -225,15 +235,19 @@ export class VueElement
225
235
private _slots ?: Record < string , Node [ ] >
226
236
227
237
constructor (
238
+ /**
239
+ * Component def - note this may be an AsyncWrapper, and this._def will
240
+ * be overwritten by the inner component when resolved.
241
+ */
228
242
private _def : InnerComponentDef ,
229
243
private _props : Record < string , any > = { } ,
230
- hydrate ?: RootHydrateFunction ,
244
+ private _createApp : CreateAppFunction < Element > = createApp ,
231
245
) {
232
246
super ( )
233
- // TODO handle non-shadowRoot hydration
234
- if ( this . shadowRoot && hydrate ) {
235
- hydrate ( this . _createVNode ( ) , this . shadowRoot )
247
+ if ( this . shadowRoot && _createApp !== createApp ) {
236
248
this . _root = this . shadowRoot
249
+ // TODO hydration needs to be reworked
250
+ this . _mount ( _def )
237
251
} else {
238
252
if ( __DEV__ && this . shadowRoot ) {
239
253
warn (
@@ -303,9 +317,10 @@ export class VueElement
303
317
this . _ob . disconnect ( )
304
318
this . _ob = null
305
319
}
306
- render ( null , this . _root )
320
+ // unmount
321
+ this . _app && this . _app . unmount ( )
307
322
this . _instance ! . ce = undefined
308
- this . _instance = null
323
+ this . _app = this . _instance = null
309
324
}
310
325
} )
311
326
}
@@ -371,11 +386,8 @@ export class VueElement
371
386
)
372
387
}
373
388
374
- // initial render
375
- this . _update ( )
376
-
377
- // apply expose
378
- this . _applyExpose ( )
389
+ // initial mount
390
+ this . _mount ( def )
379
391
}
380
392
381
393
const asyncDef = ( this . _def as ComponentOptions ) . __asyncLoader
@@ -388,6 +400,34 @@ export class VueElement
388
400
}
389
401
}
390
402
403
+ private _mount ( def : InnerComponentDef ) {
404
+ if ( ( __DEV__ || __FEATURE_PROD_DEVTOOLS__ ) && ! def . name ) {
405
+ // @ts -expect-error
406
+ def . name = 'VueElement'
407
+ }
408
+ this . _app = this . _createApp ( def )
409
+ if ( def . configureApp ) {
410
+ def . configureApp ( this . _app )
411
+ }
412
+ this . _app . _ceVNode = this . _createVNode ( )
413
+ this . _app . mount ( this . _root )
414
+
415
+ // apply expose after mount
416
+ const exposed = this . _instance && this . _instance . exposed
417
+ if ( ! exposed ) return
418
+ for ( const key in exposed ) {
419
+ if ( ! hasOwn ( this , key ) ) {
420
+ // exposed properties are readonly
421
+ Object . defineProperty ( this , key , {
422
+ // unwrap ref to be consistent with public instance behavior
423
+ get : ( ) => unref ( exposed [ key ] ) ,
424
+ } )
425
+ } else if ( __DEV__ ) {
426
+ warn ( `Exposed property "${ key } " already exists on custom element.` )
427
+ }
428
+ }
429
+ }
430
+
391
431
private _resolveProps ( def : InnerComponentDef ) {
392
432
const { props } = def
393
433
const declaredPropKeys = isArray ( props ) ? props : Object . keys ( props || { } )
@@ -412,22 +452,6 @@ export class VueElement
412
452
}
413
453
}
414
454
415
- private _applyExpose ( ) {
416
- const exposed = this . _instance && this . _instance . exposed
417
- if ( ! exposed ) return
418
- for ( const key in exposed ) {
419
- if ( ! hasOwn ( this , key ) ) {
420
- // exposed properties are readonly
421
- Object . defineProperty ( this , key , {
422
- // unwrap ref to be consistent with public instance behavior
423
- get : ( ) => unref ( exposed [ key ] ) ,
424
- } )
425
- } else if ( __DEV__ ) {
426
- warn ( `Exposed property "${ key } " already exists on custom element.` )
427
- }
428
- }
429
- }
430
-
431
455
protected _setAttr ( key : string ) {
432
456
if ( key . startsWith ( 'data-v-' ) ) return
433
457
let value = this . hasAttribute ( key ) ? this . getAttribute ( key ) : undefined
@@ -534,7 +558,7 @@ export class VueElement
534
558
}
535
559
this . _styleChildren . add ( owner )
536
560
}
537
- const nonce = this . _def . nonce
561
+ const nonce = this . _nonce
538
562
for ( let i = styles . length - 1 ; i >= 0 ; i -- ) {
539
563
const s = document . createElement ( 'style' )
540
564
if ( nonce ) s . setAttribute ( 'nonce' , nonce )
0 commit comments