Просмотр исходного кода

fix(compiler-ssr): textarea with v-text directive SSR (#13975)

Alex Snezhko 5 месяцев назад
Родитель
Сommit
006a0c1011

+ 13 - 5
packages/compiler-ssr/src/transforms/ssrTransformElement.ts

@@ -122,8 +122,13 @@ export const ssrTransformElement: NodeTransform = (node, context) => {
             | InterpolationNode
             | undefined
           // If interpolation, this is dynamic <textarea> content, potentially
-          // injected by v-model and takes higher priority than v-bind value
-          if (!existingText || existingText.type !== NodeTypes.INTERPOLATION) {
+          // injected by v-model and takes higher priority than v-bind value.
+          // Additionally, directives with content overrides (v-text/v-html)
+          // have higher priority than the merged props.
+          if (
+            !hasContentOverrideDirective(node) &&
+            (!existingText || existingText.type !== NodeTypes.INTERPOLATION)
+          ) {
             // <textarea> with dynamic v-bind. We don't know if the final props
             // will contain .value, so we will have to do something special:
             // assign the merged props to a temp variable, and check whether
@@ -176,9 +181,8 @@ export const ssrTransformElement: NodeTransform = (node, context) => {
             ]
           }
         } else if (directives.length && !node.children.length) {
-          // v-text directive has higher priority than the merged props
-          const vText = findDir(node, 'text')
-          if (!vText) {
+          // v-text/v-html have higher priority than the merged props
+          if (!hasContentOverrideDirective(node)) {
             const tempId = `_temp${context.temps++}`
             propsExp.arguments = [
               createAssignmentExpression(
@@ -449,6 +453,10 @@ function findVModel(node: PlainElementNode): DirectiveNode | undefined {
   ) as DirectiveNode | undefined
 }
 
+function hasContentOverrideDirective(node: PlainElementNode): boolean {
+  return !!findDir(node, 'text') || !!findDir(node, 'html')
+}
+
 export function ssrProcessElement(
   node: PlainElementNode,
   context: SSRTransformContext,

+ 35 - 0
packages/server-renderer/__tests__/ssrDirectives.spec.ts

@@ -263,6 +263,41 @@ describe('ssr: directives', () => {
     })
   })
 
+  describe('template with v-text / v-html', () => {
+    test('element with v-html', async () => {
+      expect(
+        await renderToString(
+          createApp({
+            data: () => ({ foo: 'hello' }),
+            template: `<span v-html="foo"/>`,
+          }),
+        ),
+      ).toBe(`<span>hello</span>`)
+    })
+
+    test('textarea with v-text', async () => {
+      expect(
+        await renderToString(
+          createApp({
+            data: () => ({ foo: 'hello' }),
+            template: `<textarea v-text="foo"/>`,
+          }),
+        ),
+      ).toBe(`<textarea>hello</textarea>`)
+    })
+
+    test('textarea with v-html', async () => {
+      expect(
+        await renderToString(
+          createApp({
+            data: () => ({ foo: 'hello' }),
+            template: `<textarea v-html="foo"/>`,
+          }),
+        ),
+      ).toBe(`<textarea>hello</textarea>`)
+    })
+  })
+
   describe('vnode v-show', () => {
     test('basic', async () => {
       expect(