1
- import { defineComponent , inject , onBeforeUnmount } from "vue" ;
1
+ import { defineComponent , inject , isVNode , onBeforeUnmount , VNode } from "vue" ;
2
2
import { ssrRenderComponent } from "vue/server-renderer" ;
3
3
import util from "../../lib/util.ts" ;
4
4
@@ -7,7 +7,7 @@ export const Head = defineComponent({
7
7
setup ( _props , ctx ) {
8
8
const ssrHeadCollection : string [ ] | undefined = inject ( "ssrHeadCollection" ) ;
9
9
if ( ctx . slots . default && ssrHeadCollection ) {
10
- const children = ctx . slots . default ( ) ;
10
+ const children = parseSlots ( ctx . slots . default ( ) ) ;
11
11
children . forEach ( ( vnode ) => {
12
12
const { props } = vnode ;
13
13
// add srr attr
@@ -25,31 +25,71 @@ export const Head = defineComponent({
25
25
head . removeChild ( el ) ;
26
26
}
27
27
} ) ;
28
- } ,
29
- mounted ( ) {
30
- const { document } = window ;
31
- const insertedEls : Array < HTMLElement > = [ ] ;
28
+
32
29
if ( this . $slots . default ) {
33
- const defaultSlots = this . $slots . default ( ) ;
34
- defaultSlots . forEach ( ( vnode ) => {
35
- const { type , children } = vnode ;
36
- if ( type === "title" ) {
37
- const el = document . createElement ( type ) ;
38
- if ( util . isFilledString ( children ) ) {
39
- el . innerText = children ;
40
- } else if ( util . isFilledArray ( children ) ) {
41
- el . innerText = children . join ( "" ) ;
42
- }
43
- document . head . appendChild ( el ) ;
44
- insertedEls . push ( el ) ;
30
+ const { document } = window ;
31
+ const insertedEls : Array < HTMLElement > = [ ] ;
32
+ const children = parseSlots ( this . $slots . default ( ) ) ;
33
+ children . forEach ( ( vnode ) => {
34
+ const { type , props , children } = vnode ;
35
+ const el = document . createElement ( type ) ;
36
+ if ( children ) el . innerText = children ;
37
+ if ( props ) {
38
+ Object . keys ( props ) . forEach ( ( key ) => {
39
+ const value = props [ key ] ;
40
+ el . setAttribute ( key , String ( value || "" ) ) ;
41
+ } ) ;
45
42
}
43
+ document . head . appendChild ( el ) ;
44
+ insertedEls . push ( el ) ;
45
+ } ) ;
46
+ onBeforeUnmount ( ( ) => {
47
+ insertedEls . forEach ( ( el ) => document . head . removeChild ( el ) ) ;
46
48
} ) ;
47
49
}
48
- onBeforeUnmount ( ( ) => {
49
- insertedEls . forEach ( ( el ) => document . head . removeChild ( el ) ) ;
50
- } ) ;
51
50
} ,
52
51
render ( ) {
53
52
return [ ] ;
54
53
} ,
55
54
} ) ;
55
+
56
+ type ParseSlots = {
57
+ type : string ;
58
+ props ?: Record < string , unknown > | null ;
59
+ children ?: string | null ;
60
+ } ;
61
+
62
+ function parseSlots ( vnodes : VNode [ ] ) : ParseSlots [ ] {
63
+ const els : ParseSlots [ ] = [ ] ;
64
+ const walk = ( vnode : VNode ) => {
65
+ if ( ! isVNode ( vnode ) ) {
66
+ return ;
67
+ }
68
+
69
+ const { type, props, children } = vnode ;
70
+
71
+ switch ( type ) {
72
+ // ingore `script` and `no-script` tag
73
+ // ingore `style` tag
74
+ case "base" :
75
+ case "meta" :
76
+ case "link" :
77
+ // remove the children of base/meta/link elements
78
+ els . push ( { type, props } ) ;
79
+ break ;
80
+ case "title" :
81
+ if ( util . isFilledString ( children ) ) {
82
+ els . push ( { type, props, children } ) ;
83
+ } else if ( util . isFilledArray ( children ) ) {
84
+ els . push ( { type, props, children : children . join ( "" ) } ) ;
85
+ } else {
86
+ els . push ( { type, props } ) ;
87
+ }
88
+ break ;
89
+ }
90
+ } ;
91
+
92
+ vnodes . forEach ( ( vnode ) => walk ( vnode ) ) ;
93
+
94
+ return els ;
95
+ }
0 commit comments