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
<span>show-it </span>
+ show-it
`)
+ expect(code).toMatchSnapshot()
+ })
+
+ test('stringify v-text', () => {
+ const { code } = compileWithStringify(`
+
+ <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 += `${node.tag}>`
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)
)
]