diff --git a/packages/compiler-core/src/index.ts b/packages/compiler-core/src/index.ts index a68d2395..6ed7aa5b 100644 --- a/packages/compiler-core/src/index.ts +++ b/packages/compiler-core/src/index.ts @@ -59,6 +59,7 @@ export { PropsExpression } from './transforms/transformElement' export { processSlotOutlet } from './transforms/transformSlotOutlet' +export { getConstantType } from './transforms/hoistStatic' export { generateCodeFrame } from '@vue/shared' // v2 compat only 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 efa75df3..8427b38f 100644 --- a/packages/compiler-dom/__tests__/transforms/__snapshots__/stringifyStatic.spec.ts.snap +++ b/packages/compiler-dom/__tests__/transforms/__snapshots__/stringifyStatic.spec.ts.snap @@ -32,3 +32,23 @@ return function render(_ctx, _cache) { return (_openBlock(), _createElementBlock(\\"div\\", null, _hoisted_2)) }" `; + +exports[`stringify static html stringify v-html 1`] = ` +"const { createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode } = Vue + +const _hoisted_1 = /*#__PURE__*/_createStaticVNode(\\"
show-it 
12
\\", 2) + +return function render(_ctx, _cache) { + return _hoisted_1 +}" +`; + +exports[`stringify static html stringify v-text 1`] = ` +"const { createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode } = Vue + +const _hoisted_1 = /*#__PURE__*/_createStaticVNode(\\"
<span>show-it </span>
12
\\", 2) + +return function render(_ctx, _cache) { + return _hoisted_1 +}" +`; diff --git a/packages/compiler-dom/__tests__/transforms/stringifyStatic.spec.ts b/packages/compiler-dom/__tests__/transforms/stringifyStatic.spec.ts index 0beb4258..c737071a 100644 --- a/packages/compiler-dom/__tests__/transforms/stringifyStatic.spec.ts +++ b/packages/compiler-dom/__tests__/transforms/stringifyStatic.spec.ts @@ -433,4 +433,25 @@ describe('stringify static html', () => { ] }) }) + + // #5439 + test('stringify v-html', () => { + const { code } = compileWithStringify(` +
+
+ 12 +
`) + expect(code).toMatch(`show-it `) + expect(code).toMatchSnapshot() + }) + + test('stringify v-text', () => { + const { code } = compileWithStringify(` +
+
+ 12 +
`) + expect(code).toMatch(`<span>show-it </span>`) + expect(code).toMatchSnapshot() + }) }) diff --git a/packages/compiler-dom/src/transforms/stringifyStatic.ts b/packages/compiler-dom/src/transforms/stringifyStatic.ts index d2d0b6fe..a268d86c 100644 --- a/packages/compiler-dom/src/transforms/stringifyStatic.ts +++ b/packages/compiler-dom/src/transforms/stringifyStatic.ts @@ -279,6 +279,7 @@ function stringifyElement( context: TransformContext ): string { let res = `<${node.tag}` + let innerHTML = '' for (let i = 0; i < node.props.length; i++) { const p = node.props[i] if (p.type === NodeTypes.ATTRIBUTE) { @@ -286,28 +287,38 @@ function stringifyElement( if (p.value) { res += `="${escapeHtml(p.value.content)}"` } - } else if (p.type === NodeTypes.DIRECTIVE && p.name === 'bind') { - const exp = p.exp as SimpleExpressionNode - if (exp.content[0] === '_') { - // internally generated string constant references - // e.g. imported URL strings via compiler-sfc transformAssetUrl plugin - res += ` ${(p.arg as SimpleExpressionNode).content}="__VUE_EXP_START__${ - exp.content - }__VUE_EXP_END__"` - continue - } - // constant v-bind, e.g. :foo="1" - let evaluated = evaluateConstant(exp) - if (evaluated != null) { - const arg = p.arg && (p.arg as SimpleExpressionNode).content - if (arg === 'class') { - evaluated = normalizeClass(evaluated) - } else if (arg === 'style') { - evaluated = stringifyStyle(normalizeStyle(evaluated)) + } else if (p.type === NodeTypes.DIRECTIVE) { + if (p.name === 'bind') { + const exp = p.exp as SimpleExpressionNode + if (exp.content[0] === '_') { + // internally generated string constant references + // e.g. imported URL strings via compiler-sfc transformAssetUrl plugin + res += ` ${ + (p.arg as SimpleExpressionNode).content + }="__VUE_EXP_START__${exp.content}__VUE_EXP_END__"` + continue } - res += ` ${(p.arg as SimpleExpressionNode).content}="${escapeHtml( - evaluated - )}"` + // constant v-bind, e.g. :foo="1" + let evaluated = evaluateConstant(exp) + if (evaluated != null) { + const arg = p.arg && (p.arg as SimpleExpressionNode).content + if (arg === 'class') { + evaluated = normalizeClass(evaluated) + } else if (arg === 'style') { + evaluated = stringifyStyle(normalizeStyle(evaluated)) + } + res += ` ${(p.arg as SimpleExpressionNode).content}="${escapeHtml( + evaluated + )}"` + } + } else if (p.name === 'html') { + // #5439 v-html with constant value + // not sure why would anyone do this but it can happen + innerHTML = evaluateConstant(p.exp as SimpleExpressionNode) + } else if (p.name === 'text') { + innerHTML = escapeHtml( + toDisplayString(evaluateConstant(p.exp as SimpleExpressionNode)) + ) } } } @@ -315,8 +326,12 @@ function stringifyElement( res += ` ${context.scopeId}` } res += `>` - for (let i = 0; i < node.children.length; i++) { - res += stringifyNode(node.children[i], context) + if (innerHTML) { + res += innerHTML + } else { + for (let i = 0; i < node.children.length; i++) { + res += stringifyNode(node.children[i], context) + } } if (!isVoidTag(node.tag)) { res += `` diff --git a/packages/compiler-dom/src/transforms/vText.ts b/packages/compiler-dom/src/transforms/vText.ts index 862d2c20..77bf0032 100644 --- a/packages/compiler-dom/src/transforms/vText.ts +++ b/packages/compiler-dom/src/transforms/vText.ts @@ -3,7 +3,8 @@ import { createObjectProperty, createSimpleExpression, TO_DISPLAY_STRING, - createCallExpression + createCallExpression, + getConstantType } from '@vue/compiler-core' import { createDOMCompilerError, DOMErrorCodes } from '../errors' @@ -25,11 +26,13 @@ export const transformVText: DirectiveTransform = (dir, node, context) => { createObjectProperty( createSimpleExpression(`textContent`, true), exp - ? createCallExpression( - context.helperString(TO_DISPLAY_STRING), - [exp], - loc - ) + ? getConstantType(exp, context) > 0 + ? exp + : createCallExpression( + context.helperString(TO_DISPLAY_STRING), + [exp], + loc + ) : createSimpleExpression('', true) ) ]