Skip to content

Commit 006a0c1

Browse files
authored
fix(compiler-ssr): textarea with v-text directive SSR (#13975)
1 parent b8aab3d commit 006a0c1

File tree

2 files changed

+48
-5
lines changed

2 files changed

+48
-5
lines changed

packages/compiler-ssr/src/transforms/ssrTransformElement.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,13 @@ export const ssrTransformElement: NodeTransform = (node, context) => {
122122
| InterpolationNode
123123
| undefined
124124
// If interpolation, this is dynamic <textarea> content, potentially
125-
// injected by v-model and takes higher priority than v-bind value
126-
if (!existingText || existingText.type !== NodeTypes.INTERPOLATION) {
125+
// injected by v-model and takes higher priority than v-bind value.
126+
// Additionally, directives with content overrides (v-text/v-html)
127+
// have higher priority than the merged props.
128+
if (
129+
!hasContentOverrideDirective(node) &&
130+
(!existingText || existingText.type !== NodeTypes.INTERPOLATION)
131+
) {
127132
// <textarea> with dynamic v-bind. We don't know if the final props
128133
// will contain .value, so we will have to do something special:
129134
// assign the merged props to a temp variable, and check whether
@@ -176,9 +181,8 @@ export const ssrTransformElement: NodeTransform = (node, context) => {
176181
]
177182
}
178183
} else if (directives.length && !node.children.length) {
179-
// v-text directive has higher priority than the merged props
180-
const vText = findDir(node, 'text')
181-
if (!vText) {
184+
// v-text/v-html have higher priority than the merged props
185+
if (!hasContentOverrideDirective(node)) {
182186
const tempId = `_temp${context.temps++}`
183187
propsExp.arguments = [
184188
createAssignmentExpression(
@@ -449,6 +453,10 @@ function findVModel(node: PlainElementNode): DirectiveNode | undefined {
449453
) as DirectiveNode | undefined
450454
}
451455

456+
function hasContentOverrideDirective(node: PlainElementNode): boolean {
457+
return !!findDir(node, 'text') || !!findDir(node, 'html')
458+
}
459+
452460
export function ssrProcessElement(
453461
node: PlainElementNode,
454462
context: SSRTransformContext,

packages/server-renderer/__tests__/ssrDirectives.spec.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,41 @@ describe('ssr: directives', () => {
263263
})
264264
})
265265

266+
describe('template with v-text / v-html', () => {
267+
test('element with v-html', async () => {
268+
expect(
269+
await renderToString(
270+
createApp({
271+
data: () => ({ foo: 'hello' }),
272+
template: `<span v-html="foo"/>`,
273+
}),
274+
),
275+
).toBe(`<span>hello</span>`)
276+
})
277+
278+
test('textarea with v-text', async () => {
279+
expect(
280+
await renderToString(
281+
createApp({
282+
data: () => ({ foo: 'hello' }),
283+
template: `<textarea v-text="foo"/>`,
284+
}),
285+
),
286+
).toBe(`<textarea>hello</textarea>`)
287+
})
288+
289+
test('textarea with v-html', async () => {
290+
expect(
291+
await renderToString(
292+
createApp({
293+
data: () => ({ foo: 'hello' }),
294+
template: `<textarea v-html="foo"/>`,
295+
}),
296+
),
297+
).toBe(`<textarea>hello</textarea>`)
298+
})
299+
})
300+
266301
describe('vnode v-show', () => {
267302
test('basic', async () => {
268303
expect(

0 commit comments

Comments
 (0)