expect(`VNode created with invalid key (NaN)`).toHaveBeenWarned()
})
+ // #5081
+ describe('children overridden by innerHTML / textContent', () => {
+ test('warn on text children', () => {
+ createVNode('div', { innerHTML: '<span/>' }, 'hello')
+ expect(
+ `The \`innerHTML\` prop on <div> will override its children`,
+ ).toHaveBeenWarned()
+ })
+
+ test('warn on array children', () => {
+ createVNode('div', { innerHTML: '<span/>' }, [createVNode('span')])
+ expect(
+ `The \`innerHTML\` prop on <div> will override its children`,
+ ).toHaveBeenWarned()
+ })
+
+ test('warn on textContent', () => {
+ createVNode('div', { textContent: 'text' }, 'hello')
+ expect(
+ `The \`textContent\` prop on <div> will override its children`,
+ ).toHaveBeenWarned()
+ })
+
+ test('no warning when the prop is nullish', () => {
+ createVNode('div', { innerHTML: undefined }, 'hello')
+ createVNode('div', { innerHTML: null }, 'hello')
+ createVNode('div', { textContent: undefined }, 'hello')
+ expect(`will override its children`).not.toHaveBeenWarned()
+ })
+
+ test('no warning without renderable children', () => {
+ createVNode('div', { innerHTML: '<span/>' })
+ createVNode('div', { innerHTML: '<span/>' }, '')
+ createVNode('div', { innerHTML: '<span/>' }, [])
+ expect(`will override its children`).not.toHaveBeenWarned()
+ })
+
+ test('no warning for component vnodes', () => {
+ const Comp = { props: ['innerHTML'], render: () => null }
+ createVNode(Comp, { innerHTML: '<span/>' }, { default: () => 'slot' })
+ expect(`will override its children`).not.toHaveBeenWarned()
+ })
+ })
+
test('create with class component', () => {
class Component {
$props: any
warn(`VNode created with invalid key (NaN). VNode type:`, vnode.type)
}
+ // #5081 validate children that will be silently discarded by innerHTML /
+ // textContent. The template compiler already errors on `v-html` / `v-text`
+ // used with children, but render functions have no such check.
+ if (__DEV__ && props && vnode.shapeFlag & ShapeFlags.ELEMENT) {
+ const overwritingProp =
+ props.innerHTML != null
+ ? 'innerHTML'
+ : props.textContent != null
+ ? 'textContent'
+ : null
+ if (overwritingProp && hasContentChildren(vnode.children)) {
+ warn(
+ `The \`${overwritingProp}\` prop on <${vnode.type as string}> will ` +
+ `override its children. Remove either the \`${overwritingProp}\` ` +
+ `prop or the children.`,
+ )
+ }
+ }
+
// track vnode for block tree
if (
isBlockTreeEnabled > 0 &&
export { createBaseVNode as createElementVNode }
+/**
+ * dev only
+ * Whether children would actually render something. Empty text and empty
+ * arrays are ignored, mirroring the compiler's `node.children.length` check
+ * for `v-html` / `v-text`.
+ */
+function hasContentChildren(children: VNode['children']): boolean {
+ if (isString(children)) return children !== ''
+ if (isArray(children)) return children.length > 0
+ return false
+}
+
export const createVNode = (
__DEV__ ? createVNodeWithArgsTransform : _createVNode
) as typeof _createVNode