@@ -8,7 +8,10 @@ import {
8
8
normalizeVNode ,
9
9
createVNode ,
10
10
Comment ,
11
- cloneVNode
11
+ cloneVNode ,
12
+ Fragment ,
13
+ VNodeArrayChildren ,
14
+ isVNode
12
15
} from './vnode'
13
16
import { handleError , ErrorCodes } from './errorHandling'
14
17
import { PatchFlags , ShapeFlags , EMPTY_OBJ , isOn } from '@vue/shared'
@@ -80,22 +83,30 @@ export function renderComponentRoot(
80
83
}
81
84
82
85
// attr merging
86
+ // in dev mode, comments are preserved, and it's possible for a template
87
+ // to have comments along side the root element which makes it a fragment
88
+ let root = result
89
+ let setRoot : ( ( root : VNode ) => void ) | undefined = undefined
90
+ if ( __DEV__ ) {
91
+ ; [ root , setRoot ] = getChildRoot ( result )
92
+ }
93
+
83
94
if (
84
95
Component . inheritAttrs !== false &&
85
96
fallthroughAttrs &&
86
97
fallthroughAttrs !== EMPTY_OBJ
87
98
) {
88
99
if (
89
- result . shapeFlag & ShapeFlags . ELEMENT ||
90
- result . shapeFlag & ShapeFlags . COMPONENT
100
+ root . shapeFlag & ShapeFlags . ELEMENT ||
101
+ root . shapeFlag & ShapeFlags . COMPONENT
91
102
) {
92
- result = cloneVNode ( result , fallthroughAttrs )
103
+ root = cloneVNode ( root , fallthroughAttrs )
93
104
// If the child root node is a compiler optimized vnode, make sure it
94
105
// force update full props to account for the merged attrs.
95
- if ( result . dynamicChildren ) {
96
- result . patchFlag |= PatchFlags . FULL_PROPS
106
+ if ( root . dynamicChildren ) {
107
+ root . patchFlag |= PatchFlags . FULL_PROPS
97
108
}
98
- } else if ( __DEV__ && ! accessedAttrs && result . type !== Comment ) {
109
+ } else if ( __DEV__ && ! accessedAttrs && root . type !== Comment ) {
99
110
warn (
100
111
`Extraneous non-props attributes (` +
101
112
`${ Object . keys ( attrs ) . join ( ', ' ) } ) ` +
@@ -108,27 +119,33 @@ export function renderComponentRoot(
108
119
// inherit scopeId
109
120
const parentScopeId = parent && parent . type . __scopeId
110
121
if ( parentScopeId ) {
111
- result = cloneVNode ( result , { [ parentScopeId ] : '' } )
122
+ root = cloneVNode ( root , { [ parentScopeId ] : '' } )
112
123
}
113
124
// inherit directives
114
125
if ( vnode . dirs ) {
115
- if ( __DEV__ && ! isElementRoot ( result ) ) {
126
+ if ( __DEV__ && ! isElementRoot ( root ) ) {
116
127
warn (
117
128
`Runtime directive used on component with non-element root node. ` +
118
129
`The directives will not function as intended.`
119
130
)
120
131
}
121
- result . dirs = vnode . dirs
132
+ root . dirs = vnode . dirs
122
133
}
123
134
// inherit transition data
124
135
if ( vnode . transition ) {
125
- if ( __DEV__ && ! isElementRoot ( result ) ) {
136
+ if ( __DEV__ && ! isElementRoot ( root ) ) {
126
137
warn (
127
138
`Component inside <Transition> renders non-element root node ` +
128
139
`that cannot be animated.`
129
140
)
130
141
}
131
- result . transition = vnode . transition
142
+ root . transition = vnode . transition
143
+ }
144
+
145
+ if ( __DEV__ && setRoot ) {
146
+ setRoot ( root )
147
+ } else {
148
+ result = root
132
149
}
133
150
} catch ( err ) {
134
151
handleError ( err , instance , ErrorCodes . RENDER_FUNCTION )
@@ -139,6 +156,25 @@ export function renderComponentRoot(
139
156
return result
140
157
}
141
158
159
+ const getChildRoot = (
160
+ vnode : VNode
161
+ ) : [ VNode , ( ( root : VNode ) => void ) | undefined ] => {
162
+ if ( vnode . type !== Fragment ) {
163
+ return [ vnode , undefined ]
164
+ }
165
+ const rawChildren = vnode . children as VNodeArrayChildren
166
+ const children = rawChildren . filter ( child => {
167
+ return ! ( isVNode ( child ) && child . type === Comment )
168
+ } )
169
+ if ( children . length !== 1 ) {
170
+ return [ vnode , undefined ]
171
+ }
172
+ const childRoot = children [ 0 ]
173
+ const index = rawChildren . indexOf ( childRoot )
174
+ const setRoot = ( updatedRoot : VNode ) => ( rawChildren [ index ] = updatedRoot )
175
+ return [ normalizeVNode ( childRoot ) , setRoot ]
176
+ }
177
+
142
178
const getFallthroughAttrs = ( attrs : Data ) : Data | undefined => {
143
179
let res : Data | undefined
144
180
for ( const key in attrs ) {
0 commit comments