@@ -8,20 +8,24 @@ import {
8
8
NodeTypes ,
9
9
TemplateChildNode ,
10
10
ElementTypes ,
11
- createBlockStatement
11
+ createBlockStatement ,
12
+ CompilerOptions ,
13
+ isText
12
14
} from '@vue/compiler-dom'
13
- import { isString , escapeHtml } from '@vue/shared'
15
+ import { isString , escapeHtml , NO } from '@vue/shared'
16
+ import { INTERPOLATE } from './runtimeHelpers'
14
17
15
18
// Because SSR codegen output is completely different from client-side output
16
19
// (e.g. multiple elements can be concatenated into a single template literal
17
20
// instead of each getting a corresponding call), we need to apply an extra
18
21
// transform pass to convert the template AST into a fresh JS AST before
19
22
// passing it to codegen.
20
23
21
- export function ssrCodegenTransform ( ast : RootNode ) {
22
- const context = createSSRTransformContext ( )
24
+ export function ssrCodegenTransform ( ast : RootNode , options : CompilerOptions ) {
25
+ const context = createSSRTransformContext ( options )
23
26
24
- const isFragment = ast . children . length > 1
27
+ const isFragment =
28
+ ast . children . length > 1 && ! ast . children . every ( c => isText ( c ) )
25
29
if ( isFragment ) {
26
30
context . pushStringPart ( `<!---->` )
27
31
}
@@ -35,12 +39,13 @@ export function ssrCodegenTransform(ast: RootNode) {
35
39
36
40
type SSRTransformContext = ReturnType < typeof createSSRTransformContext >
37
41
38
- function createSSRTransformContext ( ) {
42
+ function createSSRTransformContext ( options : CompilerOptions ) {
39
43
const body : BlockStatement [ 'body' ] = [ ]
40
44
let currentCall : CallExpression | null = null
41
45
let currentString : TemplateLiteral | null = null
42
46
43
47
return {
48
+ options,
44
49
body,
45
50
pushStringPart ( part : TemplateLiteral [ 'elements' ] [ 0 ] ) {
46
51
if ( ! currentCall ) {
@@ -66,6 +71,7 @@ function processChildren(
66
71
children : TemplateChildNode [ ] ,
67
72
context : SSRTransformContext
68
73
) {
74
+ const isVoidTag = context . options . isVoidTag || NO
69
75
for ( let i = 0 ; i < children . length ; i ++ ) {
70
76
const child = children [ i ]
71
77
if ( child . type === NodeTypes . ELEMENT ) {
@@ -77,15 +83,20 @@ function processChildren(
77
83
if ( child . children . length ) {
78
84
processChildren ( child . children , context )
79
85
}
80
- // push closing tag
81
- context . pushStringPart ( `</${ child . tag } >` )
86
+
87
+ if ( ! isVoidTag ( child . tag ) ) {
88
+ // push closing tag
89
+ context . pushStringPart ( `</${ child . tag } >` )
90
+ }
82
91
} else if ( child . tagType === ElementTypes . COMPONENT ) {
83
92
// TODO
84
93
} else if ( child . tagType === ElementTypes . SLOT ) {
85
94
// TODO
86
95
}
87
96
} else if ( child . type === NodeTypes . TEXT ) {
88
97
context . pushStringPart ( escapeHtml ( child . content ) )
98
+ } else if ( child . type === NodeTypes . INTERPOLATION ) {
99
+ context . pushStringPart ( createCallExpression ( INTERPOLATE , [ child . content ] ) )
89
100
} else if ( child . type === NodeTypes . IF ) {
90
101
// TODO
91
102
} else if ( child . type === NodeTypes . FOR ) {
0 commit comments