feat(compiler): force dynamicSlots flag when inside v-for or v-slot

This commit is contained in:
Evan You
2019-10-03 16:27:46 -04:00
parent 4dea23f79e
commit c2fc7e3347
6 changed files with 73 additions and 16 deletions

View File

@@ -49,10 +49,10 @@ export function baseCompile(
? [
// order is important
trackVForSlotScopes,
transformExpression,
trackSlotScopes
transformExpression
]
: []),
trackSlotScopes,
optimizeText,
transformStyle,
transformSlotOutlet,

View File

@@ -59,6 +59,12 @@ export interface TransformContext extends Required<TransformOptions> {
statements: Set<string>
hoists: JSChildNode[]
identifiers: { [name: string]: number | undefined }
scopes: {
vFor: number
vSlot: number
vPre: number
vOnce: number
}
parent: ParentNode | null
childIndex: number
currentNode: RootNode | TemplateChildNode | null
@@ -86,6 +92,12 @@ function createTransformContext(
statements: new Set(),
hoists: [],
identifiers: {},
scopes: {
vFor: 0,
vSlot: 0,
vPre: 0,
vOnce: 0
},
prefixIdentifiers,
nodeTransforms,
directiveTransforms,

View File

@@ -46,7 +46,7 @@ export const transformFor = createStructuralDirectiveTransform(
)
if (parseResult) {
const { helper, addIdentifiers, removeIdentifiers } = context
const { helper, addIdentifiers, removeIdentifiers, scopes } = context
const { source, value, key, index } = parseResult
// create the loop render function expression now, and add the
@@ -79,6 +79,8 @@ export const transformFor = createStructuralDirectiveTransform(
codegenNode
})
// bookkeeping
scopes.vFor++
if (!__BROWSER__ && context.prefixIdentifiers) {
// scope management
// inject identifiers to context
@@ -88,6 +90,7 @@ export const transformFor = createStructuralDirectiveTransform(
}
return () => {
scopes.vFor--
if (!__BROWSER__ && context.prefixIdentifiers) {
value && removeIdentifiers(value)
key && removeIdentifiers(key)

View File

@@ -32,22 +32,33 @@ const isStaticExp = (p: JSChildNode): p is SimpleExpressionNode =>
const defaultFallback = createSimpleExpression(`undefined`, false)
// A NodeTransform that tracks scope identifiers for scoped slots so that they
// don't get prefixed by transformExpression. This transform is only applied
// in non-browser builds with { prefixIdentifiers: true }
// A NodeTransform that:
// 1. Tracks scope identifiers for scoped slots so that they don't get prefixed
// by transformExpression. This is only applied in non-browser builds with
// { prefixIdentifiers: true }.
// 2. Track v-slot depths so that we know a slot is inside another slot.
// Note the exit callback is executed before buildSlots() on the same node,
// so only nested slots see positive numbers.
export const trackSlotScopes: NodeTransform = (node, context) => {
if (
node.type === NodeTypes.ELEMENT &&
(node.tagType === ElementTypes.COMPONENT ||
node.tagType === ElementTypes.TEMPLATE)
) {
// We are only checking non-empty v-slot here
// since we only care about slots that introduce scope variables.
const vSlot = findDir(node, 'slot')
if (vSlot) {
const { addIdentifiers, removeIdentifiers } = context
const slotProps = vSlot.exp
slotProps && addIdentifiers(slotProps)
if (!__BROWSER__ && context.prefixIdentifiers) {
slotProps && context.addIdentifiers(slotProps)
}
context.scopes.vSlot++
return () => {
slotProps && removeIdentifiers(slotProps)
if (!__BROWSER__ && context.prefixIdentifiers) {
slotProps && context.removeIdentifiers(slotProps)
}
context.scopes.vSlot--
}
}
}
@@ -94,7 +105,12 @@ export function buildSlots(
const { children, loc } = node
const slotsProperties: Property[] = []
const dynamicSlots: (ConditionalExpression | CallExpression)[] = []
let hasDynamicSlots = false
// If the slot is inside a v-for or another v-slot, force it to be dynamic
// since it likely uses a scope variable.
// TODO: This can be further optimized to only make it dynamic when the slot
// actually uses the scope variables.
let hasDynamicSlots = context.scopes.vSlot > 0 || context.scopes.vFor > 0
// 1. Check for default slot with slotProps on component itself.
// <Comp v-slot="{ prop }"/>