]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(compiler-dom): nodes with v-once shouldn't be stringified (#13878)
authorArman Tang <td19941113@gmail.com>
Wed, 24 Sep 2025 09:13:44 +0000 (17:13 +0800)
committerGitHub <noreply@github.com>
Wed, 24 Sep 2025 09:13:44 +0000 (17:13 +0800)
packages/compiler-dom/__tests__/transforms/__snapshots__/stringifyStatic.spec.ts.snap
packages/compiler-dom/__tests__/transforms/stringifyStatic.spec.ts
packages/compiler-dom/src/transforms/stringifyStatic.ts

index 84c3024f6bfc5cdb680ecbffadcd8dfbcb64c1c7..0e3ba4ef0d13a64664f18f6865a6a41bde958911 100644 (file)
@@ -12,6 +12,24 @@ return function render(_ctx, _cache) {
 }"
 `;
 
+exports[`stringify static html > eligible content + v-once node 1`] = `
+"const { setBlockTracking: _setBlockTracking, toDisplayString: _toDisplayString, createTextVNode: _createTextVNode, createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
+
+return function render(_ctx, _cache) {
+  return (_openBlock(), _createElementBlock("div", null, [
+    _cache[0] || (
+      _setBlockTracking(-1, true),
+      (_cache[0] = _createElementVNode("div", null, [
+        _createTextVNode(_toDisplayString(_ctx.msg), 1 /* TEXT */)
+      ])).cacheIndex = 0,
+      _setBlockTracking(1),
+      _cache[0]
+    ),
+    _cache[1] || (_cache[1] = _createStaticVNode("<span class=\\"foo\\">foo</span><span class=\\"foo\\">foo</span><span class=\\"foo\\">foo</span><span class=\\"foo\\">foo</span><span class=\\"foo\\">foo</span>", 5))
+  ]))
+}"
+`;
+
 exports[`stringify static html > escape 1`] = `
 "const { toDisplayString: _toDisplayString, normalizeClass: _normalizeClass, createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
 
index f58e207d6cfedf8aac1cb4deefc8f52c1634ab38..f4f29f6cdc17f98c0c1ad8aa871b1016610267aa 100644 (file)
@@ -525,4 +525,14 @@ describe('stringify static html', () => {
 
     expect(code).toMatchSnapshot()
   })
+
+  test('eligible content + v-once node', () => {
+    const { code } = compileWithStringify(
+      `<div>
+        <div v-once>{{ msg }}</div>
+        ${repeat(`<span class="foo">foo</span>`, StringifyThresholds.ELEMENT_WITH_BINDING_COUNT)}
+      </div>`,
+    )
+    expect(code).toMatchSnapshot()
+  })
 })
index 0cda6f35ba4abcbbbb3ce01076602972caea2a2b..ba05499a914b29c2e20ccc32afdf93a2f2d32ce4 100644 (file)
@@ -17,6 +17,7 @@ import {
   type TextCallNode,
   type TransformContext,
   createCallExpression,
+  findDir,
   isStaticArgOf,
 } from '@vue/compiler-core'
 import {
@@ -213,6 +214,11 @@ function analyzeNode(node: StringifiableNode): [number, number] | false {
     return false
   }
 
+  // v-once nodes should not be stringified
+  if (node.type === NodeTypes.ELEMENT && findDir(node, 'once', true)) {
+    return false
+  }
+
   if (node.type === NodeTypes.TEXT_CALL) {
     return [1, 0]
   }