From 0714cd2bb91a21e06603c6c47f9a5e95714a4722 Mon Sep 17 00:00:00 2001 From: Arman Tang Date: Fri, 12 Sep 2025 16:51:36 +0800 Subject: [PATCH] fix(compiler-dom): nodes with v-once shouldn't be stringified --- .../__snapshots__/stringifyStatic.spec.ts.snap | 18 ++++++++++++++++++ .../transforms/stringifyStatic.spec.ts | 10 ++++++++++ .../src/transforms/stringifyStatic.ts | 6 ++++++ 3 files changed, 34 insertions(+) diff --git a/packages/compiler-dom/__tests__/transforms/__snapshots__/stringifyStatic.spec.ts.snap b/packages/compiler-dom/__tests__/transforms/__snapshots__/stringifyStatic.spec.ts.snap index 84c3024f6bf..0e3ba4ef0d1 100644 --- a/packages/compiler-dom/__tests__/transforms/__snapshots__/stringifyStatic.spec.ts.snap +++ b/packages/compiler-dom/__tests__/transforms/__snapshots__/stringifyStatic.spec.ts.snap @@ -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("foofoofoofoofoo", 5)) + ])) +}" +`; + exports[`stringify static html > escape 1`] = ` "const { toDisplayString: _toDisplayString, normalizeClass: _normalizeClass, createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue diff --git a/packages/compiler-dom/__tests__/transforms/stringifyStatic.spec.ts b/packages/compiler-dom/__tests__/transforms/stringifyStatic.spec.ts index f58e207d6cf..f4f29f6cdc1 100644 --- a/packages/compiler-dom/__tests__/transforms/stringifyStatic.spec.ts +++ b/packages/compiler-dom/__tests__/transforms/stringifyStatic.spec.ts @@ -525,4 +525,14 @@ describe('stringify static html', () => { expect(code).toMatchSnapshot() }) + + test('eligible content + v-once node', () => { + const { code } = compileWithStringify( + `
+
{{ msg }}
+ ${repeat(`foo`, StringifyThresholds.ELEMENT_WITH_BINDING_COUNT)} +
`, + ) + expect(code).toMatchSnapshot() + }) }) diff --git a/packages/compiler-dom/src/transforms/stringifyStatic.ts b/packages/compiler-dom/src/transforms/stringifyStatic.ts index 0cda6f35ba4..ba05499a914 100644 --- a/packages/compiler-dom/src/transforms/stringifyStatic.ts +++ b/packages/compiler-dom/src/transforms/stringifyStatic.ts @@ -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] }