Skip to content

Commit 3e0aef2

Browse files
committed
fix(vuejs#7913): Prevent erroneous warning when using <slot> inside slot-scope
Because slotNodes inside a slot-scope context are already set to _rendered = true after initial render, the warning for duplicate slot presence always fires when a slot-scope prop change triggers a re-render. With this change, the compiler tracks whether any slot-scoped elements have been encountered at the point the slot is compiled. If so, the direct ancestors of the slot are checked for slot-scope presence, and if found, the warning is supressed. This is admittedly not a perfect solution, as within a slot-scope context the warning now does not fire even when there _are_ duplicate slots, but I couldn't find a good way to get around that. fix vuejs#7913
1 parent 5e3823a commit 3e0aef2

File tree

3 files changed

+19
-15
lines changed

3 files changed

+19
-15
lines changed

src/compiler/codegen/index.js

+13-10
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export class CodegenState {
1818
maybeComponent: (el: ASTElement) => boolean;
1919
onceId: number;
2020
staticRenderFns: Array<string>;
21+
slotScopeinAst: boolean;
2122

2223
constructor (options: CompilerOptions) {
2324
this.options = options
@@ -29,6 +30,8 @@ export class CodegenState {
2930
this.maybeComponent = (el: ASTElement) => !isReservedTag(el.tag)
3031
this.onceId = 0
3132
this.staticRenderFns = []
33+
// we can skip checks for slot-scope parents if we haven't seen any
34+
this.slotScopeinAst = false
3235
}
3336
}
3437

@@ -50,6 +53,7 @@ export function generate (
5053
}
5154

5255
export function genElement (el: ASTElement, state: CodegenState): string {
56+
if (el.slotScope) state.slotScopeinAst = true
5357
if (el.staticRoot && !el.staticProcessed) {
5458
return genStatic(el, state)
5559
} else if (el.once && !el.onceProcessed) {
@@ -456,19 +460,18 @@ export function genComment (comment: ASTText): string {
456460
function genSlot (el: ASTElement, state: CodegenState): string {
457461
const slotName = el.slotName || '"default"'
458462
const children = genChildren(el, state)
459-
let res = `_t(${slotName}${children ? `,${children}` : ''}`
460463
const attrs = el.attrs && `{${el.attrs.map(a => `${camelize(a.name)}:${a.value}`).join(',')}}`
461464
const bind = el.attrsMap['v-bind']
462-
if ((attrs || bind) && !children) {
463-
res += `,null`
464-
}
465-
if (attrs) {
466-
res += `,${attrs}`
467-
}
468-
if (bind) {
469-
res += `${attrs ? '' : ',null'},${bind}`
465+
let inScopedSlot = false
466+
let ancestor = el
467+
if (process.env.NODE_ENV !== 'production' && state.slotScopeinAst) {
468+
while (!inScopedSlot && ancestor.parent) {
469+
if (ancestor.slotScope) inScopedSlot = true
470+
ancestor = ancestor.parent
471+
}
470472
}
471-
return res + ')'
473+
return `_t(${slotName},${children || 'null'},${attrs || 'null'},` +
474+
`${bind || 'null'},${inScopedSlot ? 'true' : 'false'})`
472475
}
473476

474477
// componentName is el.component, take it as argument to shun flow's pessimistic refinement

src/core/instance/render-helpers/render-slot.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ export function renderSlot (
99
name: string,
1010
fallback: ?Array<VNode>,
1111
props: ?Object,
12-
bindObject: ?Object
12+
bindObject: ?Object,
13+
inSlotScope: ?boolean
1314
): ?Array<VNode> {
1415
const scopedSlotFn = this.$scopedSlots[name]
1516
let nodes
@@ -29,7 +30,7 @@ export function renderSlot (
2930
const slotNodes = this.$slots[name]
3031
// warn duplicate slot usage
3132
if (slotNodes) {
32-
if (process.env.NODE_ENV !== 'production' && slotNodes._rendered) {
33+
if (process.env.NODE_ENV !== 'production' && !inSlotScope && slotNodes._rendered) {
3334
warn(
3435
`Duplicate presence of slot "${name}" found in the same render tree ` +
3536
`- this will likely cause render errors.`,

test/unit/modules/compiler/codegen.spec.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -161,21 +161,21 @@ describe('codegen', () => {
161161
it('generate single slot', () => {
162162
assertCodegen(
163163
'<div><slot></slot></div>',
164-
`with(this){return _c('div',[_t("default")],2)}`
164+
`with(this){return _c('div',[_t("default",null,null,null,false)],2)}`
165165
)
166166
})
167167

168168
it('generate named slot', () => {
169169
assertCodegen(
170170
'<div><slot name="one"></slot></div>',
171-
`with(this){return _c('div',[_t("one")],2)}`
171+
`with(this){return _c('div',[_t("one",null,null,null,false)],2)}`
172172
)
173173
})
174174

175175
it('generate slot fallback content', () => {
176176
assertCodegen(
177177
'<div><slot><div>hi</div></slot></div>',
178-
`with(this){return _c('div',[_t("default",[_c('div',[_v("hi")])])],2)}`
178+
`with(this){return _c('div',[_t("default",[_c('div',[_v("hi")])],null,null,false)],2)}`
179179
)
180180
})
181181

0 commit comments

Comments
 (0)