Skip to content

Commit

Permalink
fix(compiler-core): warn when slot used on non-root template
Browse files Browse the repository at this point in the history
Implements the warning from vue2 in vue3.

fixes #11521
  • Loading branch information
Disservin committed Aug 15, 2024
1 parent d7d0371 commit d13095b
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 2 deletions.
72 changes: 72 additions & 0 deletions packages/compiler-core/__tests__/transform.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { transformElement } from '../src/transforms/transformElement'
import { transformSlotOutlet } from '../src/transforms/transformSlotOutlet'
import { transformText } from '../src/transforms/transformText'
import { PatchFlags } from '@vue/shared'
import type { CompilerOptions } from '@vue/compiler-core'

describe('compiler: transform', () => {
test('context state', () => {
Expand Down Expand Up @@ -378,4 +379,75 @@ describe('compiler: transform', () => {
)
})
})

describe('errors', () => {
function transformWithCodegen(
template: string,
options: CompilerOptions = {},
) {
const ast = baseParse(template)
transform(ast, {
nodeTransforms: [
transformIf,
transformFor,
transformText,
transformSlotOutlet,
transformElement,
],
...options,
})
return ast
}

test('warn when v-slot used on non-root level <template>', () => {
const onError = vi.fn()

const ast = transformWithCodegen(
`
<template>
<Bar>
<template>
<template #header> Header </template>
</template>
</Bar>
</template>`,
{ onError },
)

expect(onError.mock.calls[0]).toMatchObject([
{
code: ErrorCodes.X_TEMPLATE_NOT_ROOT,
loc: (ast.children[0] as any).children[0].children[0].children[0].loc,
},
])
})

test('dont warn when v-slot used on root level <template>', () => {
const onError = vi.fn()

transformWithCodegen(
`<template>
<Comp>
<template #header> Header </template>
</Comp>
</template>`,
{ onError },
)

expect(onError.mock.calls).toEqual([])
})

test('dont warn when v-slot used on root level <template> inside custom component', () => {
const onError = vi.fn()

transformWithCodegen(
`<template>
<div is="vue:customComp"><template v-slot="slotProps"></template></div>
</template>`,
{ onError },
)

expect(onError.mock.calls).toEqual([])
})
})
})
4 changes: 4 additions & 0 deletions packages/compiler-core/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export enum ErrorCodes {
X_V_MODEL_ON_PROPS,
X_INVALID_EXPRESSION,
X_KEEP_ALIVE_INVALID_CHILDREN,
X_TEMPLATE_NOT_ROOT,

// generic errors
X_PREFIX_ID_NOT_SUPPORTED,
Expand Down Expand Up @@ -151,6 +152,9 @@ export const errorMessages: Record<ErrorCodes, string> = {
'End bracket for dynamic directive argument was not found. ' +
'Note that dynamic directive argument cannot contain spaces.',
[ErrorCodes.X_MISSING_DIRECTIVE_NAME]: 'Legal directive name was expected.',
[ErrorCodes.X_TEMPLATE_NOT_ROOT]:
`<template v-slot> can only appear at the root level inside ` +
`the receiving component`,

// transform errors
[ErrorCodes.X_V_IF_NO_EXPRESSION]: `v-if/v-else-if is missing expression.`,
Expand Down
16 changes: 15 additions & 1 deletion packages/compiler-core/src/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,12 @@ import {
isArray,
isString,
} from '@vue/shared'
import { defaultOnError, defaultOnWarn } from './errors'
import {
ErrorCodes,
createCompilerError,
defaultOnError,
defaultOnWarn,
} from './errors'
import {
CREATE_COMMENT,
FRAGMENT,
Expand Down Expand Up @@ -496,6 +501,15 @@ export function createStructuralDirectiveTransform(
// structural directive transforms are not concerned with slots
// as they are handled separately in vSlot.ts
if (node.tagType === ElementTypes.TEMPLATE && props.some(isVSlot)) {
if (
context.parent &&
'tagType' in context.parent &&
context.parent.tagType !== ElementTypes.COMPONENT
) {
context.onError(
createCompilerError(ErrorCodes.X_TEMPLATE_NOT_ROOT, node.loc),
)
}
return
}
const exitFns = []
Expand Down
2 changes: 1 addition & 1 deletion packages/compiler-dom/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export function createDOMCompilerError(
}

export enum DOMErrorCodes {
X_V_HTML_NO_EXPRESSION = 53 /* ErrorCodes.__EXTEND_POINT__ */,
X_V_HTML_NO_EXPRESSION = 54 /* ErrorCodes.__EXTEND_POINT__ */,
X_V_HTML_WITH_CHILDREN,
X_V_TEXT_NO_EXPRESSION,
X_V_TEXT_WITH_CHILDREN,
Expand Down

0 comments on commit d13095b

Please sign in to comment.