]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
refactor(compiler-vapor): dynamicFlag
author三咲智子 Kevin Deng <sxzz@sxzz.moe>
Mon, 29 Jan 2024 14:08:57 +0000 (22:08 +0800)
committer三咲智子 Kevin Deng <sxzz@sxzz.moe>
Mon, 29 Jan 2024 14:08:57 +0000 (22:08 +0800)
packages/compiler-vapor/__tests__/transforms/__snapshots__/vIf.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/vBind.spec.ts
packages/compiler-vapor/__tests__/transforms/vIf.spec.ts
packages/compiler-vapor/src/generate.ts
packages/compiler-vapor/src/ir.ts
packages/compiler-vapor/src/transform.ts
packages/compiler-vapor/src/transforms/transformInterpolation.ts
packages/compiler-vapor/src/transforms/vIf.ts

index a251ec008d74c541172a05112ac7b05b6d34ec63..bc726ca1261f9811fba2cfea1e252ba0b8c274c8 100644 (file)
@@ -21,14 +21,15 @@ export function render(_ctx) {
 `;
 
 exports[`compiler: v-if > comment between branches 1`] = `
-"import { template as _template, fragment as _fragment, createIf as _createIf, prepend as _prepend } from 'vue/vapor';
+"import { template as _template, children as _children, createIf as _createIf, prepend as _prepend, renderEffect as _renderEffect, setText as _setText } from 'vue/vapor';
 
 export function render(_ctx) {
   const t0 = _template("<div></div>")
   const t1 = _template("<!--foo--><p></p>")
   const t2 = _template("<!--bar-->fine")
-  const t3 = _fragment()
+  const t3 = _template("<input>")
   const n0 = t3()
+  const { 0: [n5],} = _children(n0)
   const n1 = _createIf(() => (_ctx.ok), () => {
     const n2 = t0()
     return n2
@@ -40,6 +41,9 @@ export function render(_ctx) {
     return n4
   }))
   _prepend(n0, n1)
+  _renderEffect(() => {
+    _setText(n5, _ctx.text)
+  })
   return n0
 }"
 `;
index 9629a9274e5dfb9e1225c1bd177c37b5cf8801c2..da02641c9dda5cd666be99f4c9ab93ecab3a7a42 100644 (file)
@@ -1,5 +1,10 @@
 import { ErrorCodes, NodeTypes } from '@vue/compiler-dom'
-import { IRNodeTypes, transformElement, transformVBind } from '../../src'
+import {
+  DynamicFlag,
+  IRNodeTypes,
+  transformElement,
+  transformVBind,
+} from '../../src'
 import { makeCompile } from './_utils'
 
 const compileWithVBind = makeCompile({
@@ -15,7 +20,7 @@ describe('compiler v-bind', () => {
 
     expect(ir.dynamic.children[0]).toMatchObject({
       id: 1,
-      referenced: true,
+      dynamicFlags: DynamicFlag.REFERENCED,
     })
     expect(ir.template[0]).toMatchObject({
       type: IRNodeTypes.TEMPLATE_FACTORY,
index 7d6cd38a1d9ea6cd90b50765794a2e498c9580ea..7f43dc1266b6bbe4abb68c52bf28a782f75d6ff1 100644 (file)
@@ -276,6 +276,7 @@ describe('compiler: v-if', () => {
       <p v-else-if="orNot"/>
       <!--bar-->
       <template v-else>fine</template>
+      <input v-text="text" />
     `)
     expect(code).matchSnapshot()
     expect(ir.template).lengthOf(4)
@@ -292,7 +293,10 @@ describe('compiler: v-if', () => {
         template: '<!--bar-->fine',
         type: IRNodeTypes.TEMPLATE_FACTORY,
       },
-      { type: IRNodeTypes.FRAGMENT_FACTORY },
+      {
+        type: IRNodeTypes.TEMPLATE_FACTORY,
+        template: '<input>',
+      },
     ])
   })
 
index 6e1b75becab363c056689a92643b8e035b7e96eb..1f2b04624a94ad70b0d981b8a0a343f8bc08878a 100644 (file)
@@ -9,6 +9,7 @@ import {
 } from '@vue/compiler-dom'
 import {
   type BlockFunctionIRNode,
+  DynamicFlag,
   type IRDynamicChildren,
   IRNodeTypes,
   type OperationNode,
@@ -317,20 +318,27 @@ function genChildren(children: IRDynamicChildren) {
   let offset = 0
   for (const [index, child] of Object.entries(children)) {
     const childrenLength = Object.keys(child.children).length
-    if (child.ghost && child.placeholder === null && childrenLength === 0) {
+    if (
+      child.dynamicFlags & DynamicFlag.NON_TEMPLATE ||
+      (child.dynamicFlags & DynamicFlag.INSERT &&
+        child.placeholder === null &&
+        childrenLength === 0)
+    ) {
       offset--
       continue
     }
 
-    code += ` ${Number(index) + offset}: [`
-
-    const id = child.ghost ? child.placeholder : child.id
-    if (id !== null) code += `n${id}`
-
+    const idx = Number(index) + offset
+    const id =
+      child.dynamicFlags & DynamicFlag.INSERT ? child.placeholder : child.id
     const childrenString = childrenLength && genChildren(child.children)
-    if (childrenString) code += `, ${childrenString}`
 
-    code += '],'
+    if (id !== null || childrenString) {
+      code += ` ${idx}: [`
+      if (id !== null) code += `n${id}`
+      if (childrenString) code += `, ${childrenString}`
+      code += '],'
+    }
   }
 
   if (!code) return ''
index 7c0872a1bd68c7de6cc7eb1aac0f5c21de093fac..40b79cf6e7f5e5b0f30c1c9d82f6f5bca46e1b51 100644 (file)
@@ -180,11 +180,25 @@ export type OperationNode =
 
 export type BlockIRNode = RootIRNode | BlockFunctionIRNode
 
+export enum DynamicFlag {
+  NONE = 0,
+  /**
+   * This node is referenced and needs to be saved as a variable.
+   */
+  REFERENCED = 1,
+  /**
+   * This node is not generated from template, but is generated dynamically.
+   */
+  NON_TEMPLATE = 1 << 1,
+  /**
+   * This node needs to be inserted back into the template.
+   */
+  INSERT = 1 << 2,
+}
+
 export interface IRDynamicInfo {
   id: number | null
-  referenced: boolean
-  /** created by DOM API */
-  ghost: boolean
+  dynamicFlags: DynamicFlag
   placeholder: number | null
   children: IRDynamicChildren
 }
index b8b3adf254c4017b414edb361547d63bac8337aa..073b4ad6a75e4ffd2f2b4faab47275b09a7d0d58 100644 (file)
@@ -14,18 +14,17 @@ import {
 } from '@vue/compiler-dom'
 import { EMPTY_OBJ, NOOP, extend, isArray, isString } from '@vue/shared'
 import {
+  type BlockIRNode,
+  DynamicFlag,
+  type FragmentFactoryIRNode,
+  type HackOptions,
   type IRDynamicInfo,
   type IRExpression,
   IRNodeTypes,
   type OperationNode,
   type RootIRNode,
-} from './ir'
-import type {
-  BlockIRNode,
-  FragmentFactoryIRNode,
-  HackOptions,
-  TemplateFactoryIRNode,
-  VaporDirectiveNode,
+  type TemplateFactoryIRNode,
+  type VaporDirectiveNode,
 } from './ir'
 
 export type NodeTransform = (
@@ -100,6 +99,13 @@ const defaultOptions = {
   onWarn: defaultOnWarn,
 }
 
+export const genDefaultDynamic = (): IRDynamicInfo => ({
+  id: null,
+  dynamicFlags: 0,
+  placeholder: null,
+  children: {},
+})
+
 // TODO use class for better perf
 function createRootContext(
   root: RootIRNode,
@@ -135,7 +141,7 @@ function createRootContext(
     increaseId: () => globalId++,
     reference() {
       if (this.dynamic.id !== null) return this.dynamic.id
-      this.dynamic.referenced = true
+      this.dynamic.dynamicFlags |= DynamicFlag.REFERENCED
       return (this.dynamic.id = this.increaseId())
     },
     registerEffect(expressions, operations) {
@@ -220,14 +226,8 @@ function createContext<T extends TemplateChildNode>(
 
     template: '',
     childrenTemplate: [],
-    dynamic: {
-      id: null,
-      referenced: false,
-      ghost: false,
-      placeholder: null,
-      children: {},
-    },
-  })
+    dynamic: genDefaultDynamic(),
+  } satisfies Partial<TransformContext<T>>)
   return ctx
 }
 
@@ -243,13 +243,9 @@ export function transform(
     loc: root.loc,
     template: [],
     templateIndex: -1,
-    dynamic: {
-      id: null,
-      referenced: true,
-      ghost: true,
-      placeholder: null,
-      children: {},
-    },
+    dynamic: extend(genDefaultDynamic(), {
+      dynamicFlags: DynamicFlag.REFERENCED | DynamicFlag.INSERT,
+    } satisfies Partial<IRDynamicInfo>),
     effect: [],
     operation: [],
   }
@@ -287,6 +283,7 @@ function transformNode(
       node = context.node
     }
   }
+
   switch (node.type) {
     case NodeTypes.ROOT:
     case NodeTypes.ELEMENT: {
@@ -322,14 +319,7 @@ function transformChildren(ctx: TransformContext<RootNode | ElementNode>) {
     const childContext = createContext(child, ctx, i)
     transformNode(childContext)
     ctx.childrenTemplate.push(childContext.template)
-    if (
-      childContext.dynamic.ghost ||
-      childContext.dynamic.referenced ||
-      childContext.dynamic.placeholder ||
-      Object.keys(childContext.dynamic.children).length
-    ) {
-      ctx.dynamic.children[i] = childContext.dynamic
-    }
+    ctx.dynamic.children[i] = childContext.dynamic
   }
 
   processDynamicChildren(ctx)
@@ -344,7 +334,7 @@ function processDynamicChildren(ctx: TransformContext<RootNode | ElementNode>) {
   for (let index = 0; index < node.children.length; index++) {
     const child = ctx.dynamic.children[index]
 
-    if (!child || !child.ghost) {
+    if (!child || !(child.dynamicFlags & DynamicFlag.INSERT)) {
       if (prevChildren.length) {
         if (hasStatic) {
           ctx.childrenTemplate[index - prevChildren.length] = `<!>`
index ac1a7142086e5b01799550877521912ddbba4f7d..27f6a2b74b1945c57204859c91a71f904397c4a6 100644 (file)
@@ -1,6 +1,6 @@
 import { NodeTypes, type SimpleExpressionNode } from '@vue/compiler-dom'
 import type { NodeTransform } from '../transform'
-import { IRNodeTypes } from '../ir'
+import { DynamicFlag, IRNodeTypes } from '../ir'
 
 export const transformInterpolation: NodeTransform = (node, ctx) => {
   if (node.type !== NodeTypes.INTERPOLATION) return
@@ -27,7 +27,7 @@ export const transformInterpolation: NodeTransform = (node, ctx) => {
     )
   } else {
     const id = ctx.reference()
-    ctx.dynamic.ghost = true
+    ctx.dynamic.dynamicFlags |= DynamicFlag.INSERT
     ctx.registerOperation({
       type: IRNodeTypes.CREATE_TEXT_NODE,
       loc: node.loc,
index 25e1c4de8b802559aebb12f815d04f7621644824..70e4523154227a49e93ddb56b92d03fe9b682c55 100644 (file)
@@ -12,9 +12,12 @@ import {
 import {
   type TransformContext,
   createStructuralDirectiveTransform,
+  genDefaultDynamic,
 } from '../transform'
 import {
   type BlockFunctionIRNode,
+  DynamicFlag,
+  type IRDynamicInfo,
   IRNodeTypes,
   type OperationNode,
   type VaporDirectiveNode,
@@ -41,7 +44,7 @@ export function processIf(
 
   if (dir.name === 'if') {
     const id = context.reference()
-    context.dynamic.ghost = true
+    context.dynamic.dynamicFlags |= DynamicFlag.INSERT
     const [branch, onExit] = createIfBranch(node, context)
 
     return () => {
@@ -55,10 +58,13 @@ export function processIf(
       })
     }
   } else {
+    context.dynamic.dynamicFlags |= DynamicFlag.NON_TEMPLATE
+
     // check the adjacent v-if
     const parent = context.parent!
     const siblings = parent.node.children
     const templates = parent.childrenTemplate
+    const siblingsDynamic = parent.dynamic.children
 
     const comments = []
     let sibling: TemplateChildNode | undefined
@@ -66,20 +72,18 @@ export function processIf(
     while (i-- >= -1) {
       sibling = siblings[i]
 
-      if (sibling) {
-        if (sibling.type === NodeTypes.COMMENT) {
-          __DEV__ && comments.unshift(sibling)
-          templates[i] = null
-          continue
-        } else if (
-          sibling.type === NodeTypes.TEXT &&
-          !sibling.content.trim().length
-        ) {
-          templates[i] = null
-          continue
-        }
+      if (
+        sibling &&
+        (sibling.type === NodeTypes.COMMENT ||
+          (sibling.type === NodeTypes.TEXT && !sibling.content.trim().length))
+      ) {
+        if (__DEV__ && sibling.type === NodeTypes.COMMENT)
+          comments.unshift(sibling)
+        siblingsDynamic[i].dynamicFlags |= DynamicFlag.NON_TEMPLATE
+        templates[i] = null
+      } else {
+        break
       }
-      break
     }
 
     const { operation } = context.block
@@ -150,13 +154,9 @@ export function createIfBranch(
     loc: node.loc,
     node,
     templateIndex: -1,
-    dynamic: {
-      id: null,
-      referenced: true,
-      ghost: true,
-      placeholder: null,
-      children: {},
-    },
+    dynamic: extend(genDefaultDynamic(), {
+      dynamicFlags: DynamicFlag.REFERENCED | DynamicFlag.INSERT,
+    } satisfies Partial<IRDynamicInfo>),
     effect: [],
     operation: [],
   }
@@ -164,7 +164,7 @@ export function createIfBranch(
   const exitBlock = context.enterBlock(branch)
   context.reference()
   const onExit = () => {
-    context.template += context.childrenTemplate.join('')
+    context.template += context.childrenTemplate.filter(Boolean).join('')
     context.registerTemplate()
     exitBlock()
   }