Просмотр исходного кода

fix(compiler-vapor): call withDirectives after created

三咲智子 Kevin Deng 2 лет назад
Родитель
Сommit
6b03b47462

+ 21 - 0
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("<div></div>")
+
+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("<div></div>")

+ 11 - 0
packages/compiler-vapor/__tests__/compile.spec.ts

@@ -201,5 +201,16 @@ describe('compile', () => {
       const code = compile(`<div v-test v-hello.world />`)
       expect(code).matchSnapshot()
     })
+
+    test('component', () => {
+      const code = compile(`
+      <Comp v-test>
+        <div v-if="true">
+          <Bar v-hello.world />
+        </div>
+      </Comp>
+      `)
+      expect(code).matchSnapshot()
+    })
   })
 })

+ 4 - 4
packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap

@@ -177,10 +177,10 @@ const t0 = _template("<input>")
 
 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))

+ 10 - 2
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<string, string[]> = Object.create(null)
 
+  block: BlockIRNode
   genEffects: Array<
     (effects: IREffect[], context: CodegenContext) => CodeFragment[]
   > = []
 
-  withId = <T>(fn: () => T, map: Record<string, string | null>): T => {
+  withId<T>(fn: () => T, map: Record<string, string | null>): 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

+ 5 - 26
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<number, WithDirectiveIRNode[]> = {}
-  for (const oper of directiveOps) {
-    if (!directiveMap[oper.element]) directiveMap[oper.element] = []
-    directiveMap[oper.element].push(oper)
-  }
-  return Object.values(directiveMap)
-}

+ 2 - 1
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() {

+ 20 - 1
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,
+  )
+}

+ 3 - 0
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, []))
   }