]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(compiler-vapor): handle numbers as static text (#13957)
authorzhiyuanzmj <260480378@qq.com>
Thu, 6 Nov 2025 05:57:19 +0000 (13:57 +0800)
committerGitHub <noreply@github.com>
Thu, 6 Nov 2025 05:57:19 +0000 (13:57 +0800)
packages/compiler-vapor/__tests__/transforms/__snapshots__/transformText.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/__snapshots__/vBind.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/transformText.spec.ts
packages/compiler-vapor/__tests__/transforms/vBind.spec.ts
packages/compiler-vapor/src/generators/text.ts
packages/compiler-vapor/src/transforms/transformText.ts
packages/compiler-vapor/src/transforms/vBind.ts
packages/compiler-vapor/src/utils.ts

index f18f8520353013ac714314de175386ae4af5e974..e1981aac172259703d71df6a7fa4c5510c576964 100644 (file)
@@ -11,6 +11,17 @@ export function render(_ctx) {
 }"
 `;
 
+exports[`compiler: text transform > constant text 1`] = `
+"import { child as _child, template as _template } from 'vue';
+const t0 = _template("<div>2 foo1 1 1 1</div>", true)
+
+export function render(_ctx) {
+  const n1 = t0()
+  const n0 = _child(n1)
+  return n1
+}"
+`;
+
 exports[`compiler: text transform > no consecutive text 1`] = `
 "import { setText as _setText, template as _template } from 'vue';
 const t0 = _template(" ")
index 4ea0db55fe5172aad4c608d1cd6e8d1e59b05704..4bbf1884d94128ac79bd61452d3827a9b50bc8d9 100644 (file)
@@ -633,7 +633,7 @@ export function render(_ctx) {
 
 exports[`compiler v-bind > with constant value 1`] = `
 "import { setProp as _setProp, template as _template } from 'vue';
-const t0 = _template("<div f=\\"foo1\\" h=\\"1\\"></div>", true)
+const t0 = _template("<div e=\\"2\\" f=\\"foo1\\" g=\\"1\\" h=\\"1\\"></div>", true)
 
 export function render(_ctx, $props, $emit, $attrs, $slots) {
   const n0 = t0()
@@ -641,8 +641,6 @@ export function render(_ctx, $props, $emit, $attrs, $slots) {
   _setProp(n0, "b", 1 > 2)
   _setProp(n0, "c", 1 + 2)
   _setProp(n0, "d", 1 ? 2 : 3)
-  _setProp(n0, "e", (2))
-  _setProp(n0, "g", 1)
   _setProp(n0, "i", true)
   _setProp(n0, "j", null)
   _setProp(n0, "k", _ctx.x)
index dbff56f2a425dad10ba7dba5532ea783a232ef2a..1c929f0f206296aab6f0548f01c25a771172c9ef 100644 (file)
@@ -54,4 +54,19 @@ describe('compiler: text transform', () => {
     expect(ir.template).toContain('<code>&lt;script&gt;</code>')
     expect(ir.template).not.toContain('<code><script></code>')
   })
+
+  test('constant text', () => {
+    const { code } = compileWithTextTransform(
+      `
+        <div>
+          {{ (2) }}
+          {{ \`foo\${1}\` }}
+          {{ 1 }}
+          {{ 1n }}
+          {{ '1' }}
+        </div>`,
+    )
+    expect(code).includes(`_template("<div>2 foo1 1 1 1</div>", true)`)
+    expect(code).toMatchSnapshot()
+  })
 })
index e96186c275c608ca8a64b5fae3027567800cde96..9c07b9de90b47002fb9bbba6df014d210e031c5a 100644 (file)
@@ -666,12 +666,12 @@ describe('compiler v-bind', () => {
     const { code } = compileWithVBind(
       `
         <div
-          :a="void 0" 
-          :b="1 > 2" 
-          :c="1 + 2" 
-          :d="1 ? 2 : 3" 
-          :e="(2)" 
-          :f="\`foo${1}\`"
+          :a="void 0"
+          :b="1 > 2"
+          :c="1 + 2"
+          :d="1 ? 2 : 3"
+          :e="(2)"
+          :f="\`foo\${1}\`"
           :g="1"
           :h="'1'"
           :i="true"
index 3ad133d9bf861684d68315be8b64c8215823d5e0..6d21d5e63cb8d1e1aa14d0f8830a86af48578fe6 100644 (file)
@@ -30,7 +30,7 @@ function combineValues(
 ): CodeFragment[] {
   return values.flatMap((value, i) => {
     let exp = genExpression(value, context)
-    if (!jsx && getLiteralExpressionValue(value) == null) {
+    if (!jsx && getLiteralExpressionValue(value, true) == null) {
       // dynamic, wrap with toDisplayString
       exp = genCall(context.helper('toDisplayString'), exp)
     }
index dd81bec1e80415d28621da677d815c941968f536..b22956305428580c9be1e7dbf6237323d5097c07 100644 (file)
@@ -11,11 +11,7 @@ import {
 } from '@vue/compiler-dom'
 import type { NodeTransform, TransformContext } from '../transform'
 import { DynamicFlag, IRNodeTypes } from '../ir'
-import {
-  getLiteralExpressionValue,
-  isConstantExpression,
-  isStaticExpression,
-} from '../utils'
+import { getLiteralExpressionValue } from '../utils'
 import { escapeHtml } from '@vue/shared'
 
 type TextLike = TextNode | InterpolationNode
@@ -108,31 +104,19 @@ function processInterpolation(context: TransformContext<InterpolationNode>) {
   context.template += ' '
   const id = context.reference()
 
-  if (values.length === 0) {
+  if (
+    values.length === 0 ||
+    (values.every(v => getLiteralExpressionValue(v) != null) &&
+      parentNode.type !== NodeTypes.ROOT)
+  ) {
     return
   }
 
-  const nonConstantExps = values.filter(v => !isConstantExpression(v))
-  const isStatic =
-    !nonConstantExps.length ||
-    nonConstantExps.every(e =>
-      isStaticExpression(e, context.options.bindingMetadata),
-    ) ||
-    context.inVOnce
-
-  if (isStatic) {
-    context.registerOperation({
-      type: IRNodeTypes.SET_TEXT,
-      element: id,
-      values,
-    })
-  } else {
-    context.registerEffect(values, {
-      type: IRNodeTypes.SET_TEXT,
-      element: id,
-      values,
-    })
-  }
+  context.registerEffect(values, {
+    type: IRNodeTypes.SET_TEXT,
+    element: id,
+    values,
+  })
 }
 
 function processTextContainer(
@@ -141,7 +125,7 @@ function processTextContainer(
 ) {
   const values = processTextLikeChildren(children, context)
 
-  const literals = values.map(getLiteralExpressionValue)
+  const literals = values.map(value => getLiteralExpressionValue(value))
 
   if (literals.every(l => l != null)) {
     context.childrenTemplate = literals.map(l => escapeHtml(String(l)))
index dc56eb34b4e1466cddbf313bc2dfc7c94e2d20ee..86efa86697784c4a07818ded52a273b11f877b58 100644 (file)
@@ -1,4 +1,5 @@
 import {
+  ElementTypes,
   ErrorCodes,
   NodeTypes,
   type SimpleExpressionNode,
@@ -46,7 +47,8 @@ export const transformVBind: DirectiveTransform = (dir, node, context) => {
     exp = createSimpleExpression('', true, loc)
   }
 
-  exp = resolveExpression(exp)
+  const isComponent = node.tagType === ElementTypes.COMPONENT
+  exp = resolveExpression(exp, isComponent)
   arg = resolveExpression(arg)
 
   if (arg.isStatic && isReservedProp(arg.content)) return
index 955273b1eda45e063fd1f233fa43fcf6b66c5c7a..5914471371fdc443d49e1b90f3b72d7ec239c2f4 100644 (file)
@@ -1,4 +1,3 @@
-import type { BigIntLiteral, NumericLiteral, StringLiteral } from '@babel/types'
 import { isGloballyAllowed } from '@vue/shared'
 import {
   type AttributeNode,
@@ -64,11 +63,12 @@ export function isStaticExpression(
 
 export function resolveExpression(
   exp: SimpleExpressionNode,
+  isComponent?: boolean,
 ): SimpleExpressionNode {
   if (!exp.isStatic) {
-    const value = getLiteralExpressionValue(exp)
+    const value = getLiteralExpressionValue(exp, isComponent)
     if (value !== null) {
-      return createSimpleExpression('' + value, true, exp.loc)
+      return createSimpleExpression(value, true, exp.loc)
     }
   }
   return exp
@@ -76,15 +76,32 @@ export function resolveExpression(
 
 export function getLiteralExpressionValue(
   exp: SimpleExpressionNode,
-): number | string | boolean | null {
+  excludeNumber?: boolean,
+): string | null {
   if (exp.ast) {
     if (exp.ast.type === 'StringLiteral') {
-      return (exp.ast as StringLiteral | NumericLiteral | BigIntLiteral).value
+      return exp.ast.value
     } else if (
-      exp.ast.type === 'TemplateLiteral' &&
-      exp.ast.expressions.length === 0
+      !excludeNumber &&
+      (exp.ast.type === 'NumericLiteral' || exp.ast.type === 'BigIntLiteral')
     ) {
-      return exp.ast.quasis[0].value.cooked!
+      return String(exp.ast.value)
+    } else if (exp.ast.type === 'TemplateLiteral') {
+      let result = ''
+      for (const [index, quasi] of exp.ast.quasis.entries()) {
+        result += quasi.value.cooked!
+        if (exp.ast.expressions[index]) {
+          let expressionValue = getLiteralExpressionValue({
+            ast: exp.ast.expressions[index],
+          } as SimpleExpressionNode)
+          if (expressionValue == null) {
+            return null
+          } else {
+            result += expressionValue
+          }
+        }
+      }
+      return result
     }
   }
   return exp.isStatic ? exp.content : null