mirror of https://github.com/vuejs/core.git
feat(compiler/runtime-vapor): implement v-slots + v-for / v-if (#207)
Co-authored-by: Rizumu Ayaka <rizumu@ayaka.moe> Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
This commit is contained in:
parent
2e2f3e2b96
commit
4e13a57d9c
|
@ -17,6 +17,78 @@ export function render(_ctx) {
|
|||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: transform slot > dynamic slots name w/ v-for 1`] = `
|
||||
"import { resolveComponent as _resolveComponent, createComponent as _createComponent, createForSlots as _createForSlots, template as _template } from 'vue/vapor';
|
||||
const t0 = _template("foo")
|
||||
|
||||
export function render(_ctx) {
|
||||
const _component_Comp = _resolveComponent("Comp")
|
||||
const n2 = _createComponent(_component_Comp, null, null, () => [_createForSlots(_ctx.list, (item) => ({
|
||||
name: item,
|
||||
fn: () => {
|
||||
const n0 = t0()
|
||||
return n0
|
||||
}
|
||||
}))], true)
|
||||
return n2
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: transform slot > dynamic slots name w/ v-for and provide absent key 1`] = `
|
||||
"import { resolveComponent as _resolveComponent, createComponent as _createComponent, createForSlots as _createForSlots, template as _template } from 'vue/vapor';
|
||||
const t0 = _template("foo")
|
||||
|
||||
export function render(_ctx) {
|
||||
const _component_Comp = _resolveComponent("Comp")
|
||||
const n2 = _createComponent(_component_Comp, null, null, () => [_createForSlots(_ctx.list, (_, __, index) => ({
|
||||
name: index,
|
||||
fn: () => {
|
||||
const n0 = t0()
|
||||
return n0
|
||||
}
|
||||
}))], true)
|
||||
return n2
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: transform slot > dynamic slots name w/ v-if / v-else[-if] 1`] = `
|
||||
"import { resolveComponent as _resolveComponent, createComponent as _createComponent, template as _template } from 'vue/vapor';
|
||||
const t0 = _template("condition slot")
|
||||
const t1 = _template("another condition")
|
||||
const t2 = _template("else condition")
|
||||
|
||||
export function render(_ctx) {
|
||||
const _component_Comp = _resolveComponent("Comp")
|
||||
const n6 = _createComponent(_component_Comp, null, null, () => [_ctx.condition
|
||||
? {
|
||||
name: "condition",
|
||||
fn: () => {
|
||||
const n0 = t0()
|
||||
return n0
|
||||
},
|
||||
key: "0"
|
||||
}
|
||||
: _ctx.anotherCondition
|
||||
? {
|
||||
name: "condition",
|
||||
fn: () => {
|
||||
const n2 = t1()
|
||||
return n2
|
||||
},
|
||||
key: "1"
|
||||
}
|
||||
: {
|
||||
name: "condition",
|
||||
fn: () => {
|
||||
const n4 = t2()
|
||||
return n4
|
||||
},
|
||||
key: "2"
|
||||
}], true)
|
||||
return n6
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: transform slot > implicit default slot 1`] = `
|
||||
"import { resolveComponent as _resolveComponent, createComponent as _createComponent, template as _template } from 'vue/vapor';
|
||||
const t0 = _template("<div></div>")
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { ErrorCodes, NodeTypes } from '@vue/compiler-core'
|
||||
import {
|
||||
DynamicSlotType,
|
||||
IRNodeTypes,
|
||||
transformChildren,
|
||||
transformElement,
|
||||
|
@ -126,6 +127,112 @@ describe('compiler: transform slot', () => {
|
|||
])
|
||||
})
|
||||
|
||||
test('dynamic slots name w/ v-for', () => {
|
||||
const { ir, code } = compileWithSlots(
|
||||
`<Comp>
|
||||
<template v-for="item in list" #[item]>foo</template>
|
||||
</Comp>`,
|
||||
)
|
||||
expect(code).toMatchSnapshot()
|
||||
expect(ir.block.operation[0].type).toBe(IRNodeTypes.CREATE_COMPONENT_NODE)
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Comp',
|
||||
slots: undefined,
|
||||
dynamicSlots: [
|
||||
{
|
||||
name: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'item',
|
||||
isStatic: false,
|
||||
},
|
||||
fn: { type: IRNodeTypes.BLOCK },
|
||||
loop: {
|
||||
source: { content: 'list' },
|
||||
value: { content: 'item' },
|
||||
key: undefined,
|
||||
index: undefined,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
test('dynamic slots name w/ v-for and provide absent key', () => {
|
||||
const { ir, code } = compileWithSlots(
|
||||
`<Comp>
|
||||
<template v-for="(,,index) in list" #[index]>foo</template>
|
||||
</Comp>`,
|
||||
)
|
||||
expect(code).toMatchSnapshot()
|
||||
expect(ir.block.operation[0].type).toBe(IRNodeTypes.CREATE_COMPONENT_NODE)
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Comp',
|
||||
slots: undefined,
|
||||
dynamicSlots: [
|
||||
{
|
||||
name: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'index',
|
||||
isStatic: false,
|
||||
},
|
||||
fn: { type: IRNodeTypes.BLOCK },
|
||||
loop: {
|
||||
source: { content: 'list' },
|
||||
value: undefined,
|
||||
key: undefined,
|
||||
index: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
test('dynamic slots name w/ v-if / v-else[-if]', () => {
|
||||
const { ir, code } = compileWithSlots(
|
||||
`<Comp>
|
||||
<template v-if="condition" #condition>condition slot</template>
|
||||
<template v-else-if="anotherCondition" #condition>another condition</template>
|
||||
<template v-else #condition>else condition</template>
|
||||
</Comp>`,
|
||||
)
|
||||
expect(code).toMatchSnapshot()
|
||||
expect(ir.block.operation[0].type).toBe(IRNodeTypes.CREATE_COMPONENT_NODE)
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Comp',
|
||||
slots: undefined,
|
||||
dynamicSlots: [
|
||||
{
|
||||
slotType: DynamicSlotType.CONDITIONAL,
|
||||
condition: { content: 'condition' },
|
||||
positive: {
|
||||
slotType: DynamicSlotType.BASIC,
|
||||
key: 0,
|
||||
},
|
||||
negative: {
|
||||
slotType: DynamicSlotType.CONDITIONAL,
|
||||
condition: { content: 'anotherCondition' },
|
||||
positive: {
|
||||
slotType: DynamicSlotType.BASIC,
|
||||
key: 1,
|
||||
},
|
||||
negative: { slotType: DynamicSlotType.BASIC, key: 2 },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
describe('errors', () => {
|
||||
test('error on extraneous children w/ named default slot', () => {
|
||||
const onError = vi.fn()
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
import { camelize, extend, isArray } from '@vue/shared'
|
||||
import type { CodegenContext } from '../generate'
|
||||
import {
|
||||
type ComponentBasicDynamicSlot,
|
||||
type ComponentConditionalDynamicSlot,
|
||||
type ComponentDynamicSlot,
|
||||
type ComponentLoopDynamicSlot,
|
||||
type ComponentSlots,
|
||||
type CreateComponentIRNode,
|
||||
DynamicSlotType,
|
||||
IRDynamicPropsKind,
|
||||
type IRProp,
|
||||
type IRProps,
|
||||
|
@ -15,6 +19,8 @@ import {
|
|||
DELIMITERS_ARRAY_NEWLINE,
|
||||
DELIMITERS_OBJECT,
|
||||
DELIMITERS_OBJECT_NEWLINE,
|
||||
INDENT_END,
|
||||
INDENT_START,
|
||||
NEWLINE,
|
||||
genCall,
|
||||
genMulti,
|
||||
|
@ -155,13 +161,90 @@ function genDynamicSlots(
|
|||
) {
|
||||
const slotsExpr = genMulti(
|
||||
dynamicSlots.length > 1 ? DELIMITERS_ARRAY_NEWLINE : DELIMITERS_ARRAY,
|
||||
...dynamicSlots.map(({ name, fn }) =>
|
||||
genMulti(
|
||||
DELIMITERS_OBJECT_NEWLINE,
|
||||
['name: ', ...genExpression(name, context)],
|
||||
['fn: ', ...genBlock(fn, context)],
|
||||
),
|
||||
),
|
||||
...dynamicSlots.map(slot => genDynamicSlot(slot, context)),
|
||||
)
|
||||
return ['() => ', ...slotsExpr]
|
||||
}
|
||||
|
||||
function genDynamicSlot(
|
||||
slot: ComponentDynamicSlot,
|
||||
context: CodegenContext,
|
||||
): CodeFragment[] {
|
||||
switch (slot.slotType) {
|
||||
case DynamicSlotType.BASIC:
|
||||
return genBasicDynamicSlot(slot, context)
|
||||
case DynamicSlotType.LOOP:
|
||||
return genLoopSlot(slot, context)
|
||||
case DynamicSlotType.CONDITIONAL:
|
||||
return genConditionalSlot(slot, context)
|
||||
}
|
||||
}
|
||||
|
||||
function genBasicDynamicSlot(
|
||||
slot: ComponentBasicDynamicSlot,
|
||||
context: CodegenContext,
|
||||
): CodeFragment[] {
|
||||
const { name, fn, key } = slot
|
||||
return genMulti(
|
||||
DELIMITERS_OBJECT_NEWLINE,
|
||||
['name: ', ...genExpression(name, context)],
|
||||
['fn: ', ...genBlock(fn, context)],
|
||||
...(key !== undefined ? [`key: "${key}"`] : []),
|
||||
)
|
||||
}
|
||||
|
||||
function genLoopSlot(
|
||||
slot: ComponentLoopDynamicSlot,
|
||||
context: CodegenContext,
|
||||
): CodeFragment[] {
|
||||
const { name, fn, loop } = slot
|
||||
const { value, key, index, source } = loop
|
||||
const rawValue = value && value.content
|
||||
const rawKey = key && key.content
|
||||
const rawIndex = index && index.content
|
||||
|
||||
const idMap: Record<string, string> = {}
|
||||
if (rawValue) idMap[rawValue] = rawValue
|
||||
if (rawKey) idMap[rawKey] = rawKey
|
||||
if (rawIndex) idMap[rawIndex] = rawIndex
|
||||
const slotExpr = genMulti(
|
||||
DELIMITERS_OBJECT_NEWLINE,
|
||||
['name: ', ...context.withId(() => genExpression(name, context), idMap)],
|
||||
['fn: ', ...context.withId(() => genBlock(fn, context), idMap)],
|
||||
)
|
||||
return [
|
||||
...genCall(
|
||||
context.vaporHelper('createForSlots'),
|
||||
genExpression(source, context),
|
||||
[
|
||||
...genMulti(
|
||||
['(', ')', ', '],
|
||||
rawValue ? rawValue : rawKey || rawIndex ? '_' : undefined,
|
||||
rawKey ? rawKey : rawIndex ? '__' : undefined,
|
||||
rawIndex,
|
||||
),
|
||||
' => (',
|
||||
...slotExpr,
|
||||
')',
|
||||
],
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
function genConditionalSlot(
|
||||
slot: ComponentConditionalDynamicSlot,
|
||||
context: CodegenContext,
|
||||
): CodeFragment[] {
|
||||
const { condition, positive, negative } = slot
|
||||
return [
|
||||
...genExpression(condition, context),
|
||||
INDENT_START,
|
||||
NEWLINE,
|
||||
'? ',
|
||||
...genDynamicSlot(positive, context),
|
||||
NEWLINE,
|
||||
': ',
|
||||
...(negative ? [...genDynamicSlot(negative, context)] : ['void 0']),
|
||||
INDENT_END,
|
||||
]
|
||||
}
|
||||
|
|
|
@ -73,13 +73,16 @@ export interface IfIRNode extends BaseIRNode {
|
|||
once?: boolean
|
||||
}
|
||||
|
||||
export interface ForIRNode extends BaseIRNode {
|
||||
type: IRNodeTypes.FOR
|
||||
id: number
|
||||
export interface IRFor {
|
||||
source: SimpleExpressionNode
|
||||
value?: SimpleExpressionNode
|
||||
key?: SimpleExpressionNode
|
||||
index?: SimpleExpressionNode
|
||||
}
|
||||
|
||||
export interface ForIRNode extends BaseIRNode, IRFor {
|
||||
type: IRNodeTypes.FOR
|
||||
id: number
|
||||
keyProp?: SimpleExpressionNode
|
||||
render: BlockIRNode
|
||||
once: boolean
|
||||
|
@ -208,12 +211,39 @@ export interface ComponentSlotBlockIRNode extends BlockIRNode {
|
|||
// TODO slot props
|
||||
}
|
||||
export type ComponentSlots = Record<string, ComponentSlotBlockIRNode>
|
||||
export interface ComponentDynamicSlot {
|
||||
|
||||
export enum DynamicSlotType {
|
||||
BASIC,
|
||||
LOOP,
|
||||
CONDITIONAL,
|
||||
}
|
||||
|
||||
export interface ComponentBasicDynamicSlot {
|
||||
slotType: DynamicSlotType.BASIC
|
||||
name: SimpleExpressionNode
|
||||
fn: ComponentSlotBlockIRNode
|
||||
key?: string
|
||||
key?: number
|
||||
}
|
||||
|
||||
export interface ComponentLoopDynamicSlot {
|
||||
slotType: DynamicSlotType.LOOP
|
||||
name: SimpleExpressionNode
|
||||
fn: ComponentSlotBlockIRNode
|
||||
loop: IRFor
|
||||
}
|
||||
|
||||
export interface ComponentConditionalDynamicSlot {
|
||||
slotType: DynamicSlotType.CONDITIONAL
|
||||
condition: SimpleExpressionNode
|
||||
positive: ComponentBasicDynamicSlot
|
||||
negative?: ComponentBasicDynamicSlot | ComponentConditionalDynamicSlot
|
||||
}
|
||||
|
||||
export type ComponentDynamicSlot =
|
||||
| ComponentBasicDynamicSlot
|
||||
| ComponentLoopDynamicSlot
|
||||
| ComponentConditionalDynamicSlot
|
||||
|
||||
export interface CreateComponentIRNode extends BaseIRNode {
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE
|
||||
id: number
|
||||
|
|
|
@ -10,7 +10,15 @@ import {
|
|||
} from '@vue/compiler-core'
|
||||
import type { NodeTransform, TransformContext } from '../transform'
|
||||
import { newBlock } from './utils'
|
||||
import { type BlockIRNode, DynamicFlag, type VaporDirectiveNode } from '../ir'
|
||||
import {
|
||||
type BlockIRNode,
|
||||
type ComponentBasicDynamicSlot,
|
||||
type ComponentConditionalDynamicSlot,
|
||||
DynamicFlag,
|
||||
DynamicSlotType,
|
||||
type IRFor,
|
||||
type VaporDirectiveNode,
|
||||
} from '../ir'
|
||||
import { findDir, resolveExpression } from '../utils'
|
||||
|
||||
// TODO dynamic slots
|
||||
|
@ -69,6 +77,9 @@ export const transformVSlot: NodeTransform = (node, context) => {
|
|||
|
||||
context.dynamic.flags |= DynamicFlag.NON_TEMPLATE
|
||||
|
||||
const vFor = findDir(node, 'for')
|
||||
const vIf = findDir(node, 'if')
|
||||
const vElse = findDir(node, /^else(-if)?$/, true /* allowEmpty */)
|
||||
const slots = context.slots!
|
||||
const dynamicSlots = context.dynamicSlots!
|
||||
|
||||
|
@ -79,7 +90,7 @@ export const transformVSlot: NodeTransform = (node, context) => {
|
|||
|
||||
arg &&= resolveExpression(arg)
|
||||
|
||||
if (!arg || arg.isStatic) {
|
||||
if ((!arg || arg.isStatic) && !vFor && !vIf && !vElse) {
|
||||
const slotName = arg ? arg.content : 'default'
|
||||
|
||||
if (slots[slotName]) {
|
||||
|
@ -92,12 +103,75 @@ export const transformVSlot: NodeTransform = (node, context) => {
|
|||
} else {
|
||||
slots[slotName] = block
|
||||
}
|
||||
} else if (vIf) {
|
||||
dynamicSlots.push({
|
||||
slotType: DynamicSlotType.CONDITIONAL,
|
||||
condition: vIf.exp!,
|
||||
positive: {
|
||||
slotType: DynamicSlotType.BASIC,
|
||||
name: arg!,
|
||||
fn: block,
|
||||
key: 0,
|
||||
},
|
||||
})
|
||||
} else if (vElse) {
|
||||
const vIfIR = dynamicSlots[dynamicSlots.length - 1]
|
||||
if (vIfIR.slotType === DynamicSlotType.CONDITIONAL) {
|
||||
let ifNode = vIfIR
|
||||
while (
|
||||
ifNode.negative &&
|
||||
ifNode.negative.slotType === DynamicSlotType.CONDITIONAL
|
||||
)
|
||||
ifNode = ifNode.negative
|
||||
const negative:
|
||||
| ComponentBasicDynamicSlot
|
||||
| ComponentConditionalDynamicSlot = vElse.exp
|
||||
? {
|
||||
slotType: DynamicSlotType.CONDITIONAL,
|
||||
condition: vElse.exp,
|
||||
positive: {
|
||||
slotType: DynamicSlotType.BASIC,
|
||||
name: arg!,
|
||||
fn: block,
|
||||
key: ifNode.positive.key! + 1,
|
||||
},
|
||||
}
|
||||
: {
|
||||
slotType: DynamicSlotType.BASIC,
|
||||
name: arg!,
|
||||
fn: block,
|
||||
key: ifNode.positive.key! + 1,
|
||||
}
|
||||
ifNode.negative = negative
|
||||
} else {
|
||||
context.options.onError(
|
||||
createCompilerError(ErrorCodes.X_V_ELSE_NO_ADJACENT_IF, vElse.loc),
|
||||
)
|
||||
}
|
||||
} else if (vFor) {
|
||||
if (vFor.forParseResult) {
|
||||
dynamicSlots.push({
|
||||
slotType: DynamicSlotType.LOOP,
|
||||
name: arg!,
|
||||
fn: block,
|
||||
loop: vFor.forParseResult as IRFor,
|
||||
})
|
||||
} else {
|
||||
context.options.onError(
|
||||
createCompilerError(
|
||||
ErrorCodes.X_V_FOR_MALFORMED_EXPRESSION,
|
||||
vFor.loc,
|
||||
),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
dynamicSlots.push({
|
||||
name: arg,
|
||||
slotType: DynamicSlotType.BASIC,
|
||||
name: arg!,
|
||||
fn: block,
|
||||
})
|
||||
}
|
||||
|
||||
return () => onExit()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import { renderEffect } from './renderEffect'
|
|||
import { type Block, type Fragment, fragmentKey } from './apiRender'
|
||||
import { warn } from './warning'
|
||||
import { componentKey } from './component'
|
||||
import type { DynamicSlot } from './componentSlots'
|
||||
|
||||
interface ForBlock extends Fragment {
|
||||
scope: EffectScope
|
||||
|
@ -301,44 +302,57 @@ export const createFor = (
|
|||
remove(nodes, parent!)
|
||||
scope.stop()
|
||||
}
|
||||
}
|
||||
|
||||
function getLength(source: any): number {
|
||||
if (isArray(source) || isString(source)) {
|
||||
return source.length
|
||||
} else if (typeof source === 'number') {
|
||||
if (__DEV__ && !Number.isInteger(source)) {
|
||||
warn(`The v-for range expect an integer value but got ${source}.`)
|
||||
}
|
||||
return source
|
||||
} else if (isObject(source)) {
|
||||
if (source[Symbol.iterator as any]) {
|
||||
return Array.from(source as Iterable<any>).length
|
||||
} else {
|
||||
return Object.keys(source).length
|
||||
}
|
||||
}
|
||||
return 0
|
||||
export function createForSlots(
|
||||
source: any[] | Record<any, any> | number | Set<any> | Map<any, any>,
|
||||
getSlot: (item: any, key: any, index?: number) => DynamicSlot,
|
||||
): DynamicSlot[] {
|
||||
const sourceLength = getLength(source)
|
||||
const slots = new Array<DynamicSlot>(sourceLength)
|
||||
for (let i = 0; i < sourceLength; i++) {
|
||||
const [item, key, index] = getItem(source, i)
|
||||
slots[i] = getSlot(item, key, index)
|
||||
}
|
||||
return slots
|
||||
}
|
||||
|
||||
function getItem(
|
||||
source: any,
|
||||
idx: number,
|
||||
): [item: any, key: any, index?: number] {
|
||||
if (isArray(source) || isString(source)) {
|
||||
function getLength(source: any): number {
|
||||
if (isArray(source) || isString(source)) {
|
||||
return source.length
|
||||
} else if (typeof source === 'number') {
|
||||
if (__DEV__ && !Number.isInteger(source)) {
|
||||
warn(`The v-for range expect an integer value but got ${source}.`)
|
||||
}
|
||||
return source
|
||||
} else if (isObject(source)) {
|
||||
if (source[Symbol.iterator as any]) {
|
||||
return Array.from(source as Iterable<any>).length
|
||||
} else {
|
||||
return Object.keys(source).length
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
function getItem(
|
||||
source: any,
|
||||
idx: number,
|
||||
): [item: any, key: any, index?: number] {
|
||||
if (isArray(source) || isString(source)) {
|
||||
return [source[idx], idx, undefined]
|
||||
} else if (typeof source === 'number') {
|
||||
return [idx + 1, idx, undefined]
|
||||
} else if (isObject(source)) {
|
||||
if (source && source[Symbol.iterator as any]) {
|
||||
source = Array.from(source as Iterable<any>)
|
||||
return [source[idx], idx, undefined]
|
||||
} else if (typeof source === 'number') {
|
||||
return [idx + 1, idx, undefined]
|
||||
} else if (isObject(source)) {
|
||||
if (source && source[Symbol.iterator as any]) {
|
||||
source = Array.from(source as Iterable<any>)
|
||||
return [source[idx], idx, undefined]
|
||||
} else {
|
||||
const key = Object.keys(source)[idx]
|
||||
return [source[key], key, idx]
|
||||
}
|
||||
} else {
|
||||
const key = Object.keys(source)[idx]
|
||||
return [source[key], key, idx]
|
||||
}
|
||||
return null!
|
||||
}
|
||||
return null!
|
||||
}
|
||||
|
||||
function normalizeAnchor(node: Block): Node {
|
||||
|
|
|
@ -53,11 +53,12 @@ export function initSlots(
|
|||
slots = shallowReactive(slots)
|
||||
const dynamicSlotKeys: Record<string, true> = {}
|
||||
firstEffect(instance, () => {
|
||||
const _dynamicSlots = callWithAsyncErrorHandling(
|
||||
dynamicSlots,
|
||||
instance,
|
||||
VaporErrorCodes.RENDER_FUNCTION,
|
||||
)
|
||||
const _dynamicSlots: (DynamicSlot | DynamicSlot[])[] =
|
||||
callWithAsyncErrorHandling(
|
||||
dynamicSlots,
|
||||
instance,
|
||||
VaporErrorCodes.RENDER_FUNCTION,
|
||||
)
|
||||
for (let i = 0; i < _dynamicSlots.length; i++) {
|
||||
const slot = _dynamicSlots[i]
|
||||
// array of dynamic slot generated by <template v-for="..." #[...]>
|
||||
|
|
|
@ -126,7 +126,7 @@ export {
|
|||
type FunctionPlugin,
|
||||
} from './apiCreateVaporApp'
|
||||
export { createIf } from './apiCreateIf'
|
||||
export { createFor } from './apiCreateFor'
|
||||
export { createFor, createForSlots } from './apiCreateFor'
|
||||
export { createComponent } from './apiCreateComponent'
|
||||
|
||||
export { resolveComponent, resolveDirective } from './helpers/resolveAssets'
|
||||
|
|
Loading…
Reference in New Issue