diff --git a/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap b/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap
index 2ce2fddd0..8de407e75 100644
--- a/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap
+++ b/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap
@@ -16,6 +16,18 @@ export function render(_ctx) {
}"
`;
+exports[`compile > custom directive > basic 1`] = `
+"import { template as _template, children as _children, withDirectives as _withDirectives, resolveDirective("vTest") as _resolveDirective("vTest"), resolveDirective("vHello") as _resolveDirective("vHello") } from 'vue/vapor';
+
+export function render(_ctx) {
+ const t0 = _template("
")
+ const n0 = t0()
+ const { 0: [n1],} = _children(n0)
+ _withDirectives(n1, [[_resolveDirective("vTest")], [_resolveDirective("vHello"), void 0, void 0, { world: true }]])
+ return n0
+}"
+`;
+
exports[`compile > directives > custom directive > basic 1`] = `
"import { template as _template, children as _children, withDirectives as _withDirectives } from 'vue/vapor';
diff --git a/packages/compiler-vapor/__tests__/compile.spec.ts b/packages/compiler-vapor/__tests__/compile.spec.ts
index a16b81655..23ba98882 100644
--- a/packages/compiler-vapor/__tests__/compile.spec.ts
+++ b/packages/compiler-vapor/__tests__/compile.spec.ts
@@ -207,4 +207,11 @@ describe('compile', () => {
// TODO: add more test for expression parsing (v-on, v-slot, v-for)
})
+
+ describe('custom directive', () => {
+ test('basic', () => {
+ const code = compile(``)
+ expect(code).matchSnapshot()
+ })
+ })
})
diff --git a/packages/compiler-vapor/src/generate.ts b/packages/compiler-vapor/src/generate.ts
index bba27e325..4022c5a6c 100644
--- a/packages/compiler-vapor/src/generate.ts
+++ b/packages/compiler-vapor/src/generate.ts
@@ -281,11 +281,12 @@ export function generate(
)
}
- for (const oper of ir.operation.filter(
+ const directiveOps = ir.operation.filter(
(oper): oper is WithDirectiveIRNode =>
oper.type === IRNodeTypes.WITH_DIRECTIVE,
- )) {
- genWithDirective(oper, ctx)
+ )
+ for (const directives of groupDirective(directiveOps)) {
+ genWithDirective(directives, ctx)
}
for (const operation of ir.operation) {
@@ -393,3 +394,12 @@ function genOperation(oper: OperationNode, context: CodegenContext) {
return checkNever(oper)
}
}
+
+function groupDirective(ops: WithDirectiveIRNode[]): WithDirectiveIRNode[][] {
+ const directiveMap: Record = {}
+ for (const oper of ops) {
+ if (!directiveMap[oper.element]) directiveMap[oper.element] = []
+ directiveMap[oper.element].push(oper)
+ }
+ return Object.values(directiveMap)
+}
diff --git a/packages/compiler-vapor/src/generators/directive.ts b/packages/compiler-vapor/src/generators/directive.ts
index 4b54bc5b7..0092f9ed1 100644
--- a/packages/compiler-vapor/src/generators/directive.ts
+++ b/packages/compiler-vapor/src/generators/directive.ts
@@ -5,61 +5,67 @@ import type { CodegenContext } from '../generate'
import type { WithDirectiveIRNode } from '../ir'
export function genWithDirective(
- oper: WithDirectiveIRNode,
+ opers: WithDirectiveIRNode[],
context: CodegenContext,
) {
const { push, newline, pushFnCall, pushMulti, vaporHelper, bindingMetadata } =
context
- const { dir, builtin } = oper
- // TODO merge directive for the same node
newline()
pushFnCall(
vaporHelper('withDirectives'),
// 1st arg: node
- `n${oper.element}`,
+ `n${opers[0].element}`,
// 2nd arg: directives
() => {
- push('[')
// directive
- pushMulti(['[', ']', ', '], () => {
- if (dir.name === 'show') {
- push(vaporHelper('vShow'))
- } else if (builtin) {
- push(vaporHelper(builtin))
- } else {
- const directiveReference = camelize(`v-${dir.name}`)
- // TODO resolve directive
- if (bindingMetadata[directiveReference]) {
- const directiveExpression =
- createSimpleExpression(directiveReference)
- directiveExpression.ast = null
- genExpression(directiveExpression, context)
+ pushMulti(
+ ['[', ']', ', '],
+ ...opers.map((oper) => () => {
+ push('[')
+
+ const { dir, builtin } = oper
+ if (dir.name === 'show') {
+ push(vaporHelper('vShow'))
+ } else if (builtin) {
+ push(vaporHelper(builtin))
+ } else {
+ const directiveReference = camelize(`v-${dir.name}`)
+ // TODO resolve directive
+ if (bindingMetadata[directiveReference]) {
+ const directiveExpression =
+ createSimpleExpression(directiveReference)
+ directiveExpression.ast = null
+ genExpression(directiveExpression, context)
+ } else {
+ push(vaporHelper(`resolveDirective("${directiveReference}")`))
+ }
}
- }
- if (dir.exp) {
- push(', () => ')
- genExpression(dir.exp, context)
- } else if (dir.arg || dir.modifiers.length) {
- push(', void 0')
- }
+ if (dir.exp) {
+ push(', () => ')
+ genExpression(dir.exp, context)
+ } else if (dir.arg || dir.modifiers.length) {
+ push(', void 0')
+ }
- if (dir.arg) {
- push(', ')
- genExpression(dir.arg, context)
- } else if (dir.modifiers.length) {
- push(', void 0')
- }
+ if (dir.arg) {
+ push(', ')
+ genExpression(dir.arg, context)
+ } else if (dir.modifiers.length) {
+ push(', void 0')
+ }
- if (dir.modifiers.length) {
- push(', ')
- push('{ ')
- push(genDirectiveModifiers(dir.modifiers))
- push(' }')
- }
- })
- push(']')
+ if (dir.modifiers.length) {
+ push(', ')
+ push('{ ')
+ push(genDirectiveModifiers(dir.modifiers))
+ push(' }')
+ }
+
+ push(']')
+ }),
+ )
},
)
}