diff --git a/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap b/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap index f70e66d95..1e5e4cf4f 100644 --- a/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap @@ -22,6 +22,27 @@ export function render(_ctx) { }" `; +exports[`compile > custom directive > component 1`] = ` +"import { resolveComponent as _resolveComponent, createComponent as _createComponent, resolveDirective as _resolveDirective, withDirectives as _withDirectives, insert as _insert, createIf as _createIf, template as _template } from 'vue/vapor'; +const t0 = _template("
") + +export function render(_ctx) { + const _component_Bar = _resolveComponent("Bar") + const _component_Comp = _resolveComponent("Comp") + const n0 = _createIf(() => (true), () => { + const n3 = t0() + const n2 = _createComponent(_component_Bar) + _withDirectives(n2, [[_resolveDirective("vHello"), void 0, void 0, { world: true }]]) + _insert(n2, n3) + return n3 + }) + _insert(n0, n4) + const n4 = _createComponent(_component_Comp, null, true) + _withDirectives(n4, [[_resolveDirective("vTest")]]) + return n4 +}" +`; + exports[`compile > directives > custom directive > basic 1`] = ` "import { withDirectives as _withDirectives, template as _template } from 'vue/vapor'; const t0 = _template("
") diff --git a/packages/compiler-vapor/__tests__/compile.spec.ts b/packages/compiler-vapor/__tests__/compile.spec.ts index b406d9e95..b0e31e7e7 100644 --- a/packages/compiler-vapor/__tests__/compile.spec.ts +++ b/packages/compiler-vapor/__tests__/compile.spec.ts @@ -201,5 +201,16 @@ describe('compile', () => { const code = compile(`
`) expect(code).matchSnapshot() }) + + test('component', () => { + const code = compile(` + +
+ +
+
+ `) + expect(code).matchSnapshot() + }) }) }) diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap index 7502b73bf..a8764d6e1 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap @@ -177,10 +177,10 @@ const t0 = _template("") export function render(_ctx) { const n0 = t0() - const n1 = t0() - const n2 = t0() _withDirectives(n0, [[_vModelText, () => _ctx.setupRef.child]]) + const n1 = t0() _withDirectives(n1, [[_vModelText, () => _ctx.setupLet.child]]) + const n2 = t0() _withDirectives(n2, [[_vModelText, () => _ctx.setupMaybeRef.child]]) _delegate(n0, "update:modelValue", () => $event => (_ctx.setupRef.child = $event)) _delegate(n1, "update:modelValue", () => $event => (_ctx.setupLet.child = $event)) @@ -192,10 +192,10 @@ export function render(_ctx) { exports[`compiler: vModel transform > should support member expression w/ inline 1`] = ` "(() => { const n0 = t0() - const n1 = t0() - const n2 = t0() _withDirectives(n0, [[_vModelText, () => setupRef.value.child]]) + const n1 = t0() _withDirectives(n1, [[_vModelText, () => _unref(setupLet).child]]) + const n2 = t0() _withDirectives(n2, [[_vModelText, () => _unref(setupMaybeRef).child]]) _delegate(n0, "update:modelValue", () => $event => (setupRef.value.child = $event)) _delegate(n1, "update:modelValue", () => $event => (_unref(setupLet).child = $event)) diff --git a/packages/compiler-vapor/src/generate.ts b/packages/compiler-vapor/src/generate.ts index bd36453d8..b7e55de60 100644 --- a/packages/compiler-vapor/src/generate.ts +++ b/packages/compiler-vapor/src/generate.ts @@ -3,7 +3,7 @@ import type { BaseCodegenResult, CodegenSourceMapGenerator, } from '@vue/compiler-dom' -import type { IREffect, RootIRNode, VaporHelper } from './ir' +import type { BlockIRNode, IREffect, RootIRNode, VaporHelper } from './ir' import { SourceMapGenerator } from 'source-map-js' import { extend, remove } from '@vue/shared' import { genBlockContent } from './generators/block' @@ -43,11 +43,12 @@ export class CodegenContext { identifiers: Record = Object.create(null) + block: BlockIRNode genEffects: Array< (effects: IREffect[], context: CodegenContext) => CodeFragment[] > = [] - withId = (fn: () => T, map: Record): T => { + withId(fn: () => T, map: Record): T { const { identifiers } = this const ids = Object.keys(map) @@ -62,6 +63,12 @@ export class CodegenContext { return ret } + enterBlock(block: BlockIRNode) { + const parent = this.block + this.block = block + return () => (this.block = parent) + } + constructor( public ir: RootIRNode, options: CodegenOptions, @@ -84,6 +91,7 @@ export class CodegenContext { expressionPlugins: [], } this.options = extend(defaultOptions, options) + this.block = ir.block const [code, push] = buildCodeFragment() this.code = code diff --git a/packages/compiler-vapor/src/generators/block.ts b/packages/compiler-vapor/src/generators/block.ts index 4ed4e00d4..8a5e43923 100644 --- a/packages/compiler-vapor/src/generators/block.ts +++ b/packages/compiler-vapor/src/generators/block.ts @@ -1,9 +1,4 @@ -import { - type BlockIRNode, - IRNodeTypes, - type OperationNode, - type WithDirectiveIRNode, -} from '../ir' +import type { BlockIRNode } from '../ir' import { type CodeFragment, INDENT_END, @@ -13,7 +8,6 @@ import { genCall, } from './utils' import type { CodegenContext } from '../generate' -import { genWithDirective } from './directive' import { genEffects, genOperations } from './operation' import { genChildren } from './template' import { genMulti } from './utils' @@ -38,12 +32,14 @@ export function genBlock( } export function genBlockContent( - { dynamic, effect, operation, returns }: BlockIRNode, + block: BlockIRNode, context: CodegenContext, root?: boolean, customReturns?: (returns: CodeFragment[]) => CodeFragment[], ): CodeFragment[] { const [frag, push] = buildCodeFragment() + const { dynamic, effect, operation, returns } = block + const resetBlock = context.enterBlock(block) if (root) for (const name of context.ir.component) { @@ -61,10 +57,6 @@ export function genBlockContent( push(...genChildren(child, context, child.id!)) } - for (const directives of groupDirective(operation)) { - push(...genWithDirective(directives, context)) - } - push(...genOperations(operation, context)) push( ...(context.genEffects.length @@ -80,19 +72,6 @@ export function genBlockContent( : [`n${returns[0]}`] push(...(customReturns ? customReturns(returnsCode) : returnsCode)) + resetBlock() return frag } - -function groupDirective(operation: OperationNode[]): WithDirectiveIRNode[][] { - const directiveOps = operation.filter( - (oper): oper is WithDirectiveIRNode => - oper.type === IRNodeTypes.WITH_DIRECTIVE, - ) - - const directiveMap: Record = {} - for (const oper of directiveOps) { - if (!directiveMap[oper.element]) directiveMap[oper.element] = [] - directiveMap[oper.element].push(oper) - } - return Object.values(directiveMap) -} diff --git a/packages/compiler-vapor/src/generators/component.ts b/packages/compiler-vapor/src/generators/component.ts index 34d349d41..8ab455a70 100644 --- a/packages/compiler-vapor/src/generators/component.ts +++ b/packages/compiler-vapor/src/generators/component.ts @@ -13,7 +13,7 @@ import { genExpression } from './expression' import { genPropKey } from './prop' import { createSimpleExpression } from '@vue/compiler-dom' import { genEventHandler } from './event' -import { genDirectiveModifiers } from './directive' +import { genDirectiveModifiers, genDirectivesForElement } from './directive' import { genModelHandler } from './modelValue' // TODO: generate component slots @@ -36,6 +36,7 @@ export function genCreateComponent( rawProps || (isRoot ? 'null' : false), isRoot && 'true', ), + ...genDirectivesForElement(oper.id, context), ] function genTag() { diff --git a/packages/compiler-vapor/src/generators/directive.ts b/packages/compiler-vapor/src/generators/directive.ts index 452b79f9d..9c6468b76 100644 --- a/packages/compiler-vapor/src/generators/directive.ts +++ b/packages/compiler-vapor/src/generators/directive.ts @@ -3,7 +3,16 @@ import { camelize } from '@vue/shared' import { genExpression } from './expression' import type { CodegenContext } from '../generate' import { type CodeFragment, NEWLINE, genCall, genMulti } from './utils' -import type { WithDirectiveIRNode } from '../ir' +import { + IRNodeTypes, + type OperationNode, + type WithDirectiveIRNode, +} from '../ir' + +export function genDirectivesForElement(id: number, context: CodegenContext) { + const dirs = filterDirectives(id, context.block.operation) + return dirs.length ? genWithDirective(dirs, context) : [] +} export function genWithDirective( opers: WithDirectiveIRNode[], @@ -72,3 +81,13 @@ export function genDirectiveModifiers(modifiers: string[]) { ) .join(', ') } + +function filterDirectives( + id: number, + operations: OperationNode[], +): WithDirectiveIRNode[] { + return operations.filter( + (oper): oper is WithDirectiveIRNode => + oper.type === IRNodeTypes.WITH_DIRECTIVE && oper.element === id, + ) +} diff --git a/packages/compiler-vapor/src/generators/template.ts b/packages/compiler-vapor/src/generators/template.ts index 4187e501f..0ece5bcc9 100644 --- a/packages/compiler-vapor/src/generators/template.ts +++ b/packages/compiler-vapor/src/generators/template.ts @@ -1,5 +1,6 @@ import type { CodegenContext } from '../generate' import { DynamicFlag, type IRDynamicInfo } from '../ir' +import { genDirectivesForElement } from './directive' import { type CodeFragment, NEWLINE, buildCodeFragment, genCall } from './utils' export function genTemplates( @@ -27,6 +28,7 @@ export function genChildren( if (id !== undefined && template !== undefined) { push(NEWLINE, `const n${id} = t${template}()`) + push(...genDirectivesForElement(id, context)) } let prev: [id: number, elementIndex: number] | undefined @@ -71,6 +73,7 @@ export function genChildren( ) } } + push(...genDirectivesForElement(id, context)) prev = [id, elementIndex] push(...genChildren(child, context, id, [])) }