diff --git a/packages/compiler-ssr/__tests__/ssrComponent.spec.ts b/packages/compiler-ssr/__tests__/ssrComponent.spec.ts
index 2c7f7e307..04ebb890a 100644
--- a/packages/compiler-ssr/__tests__/ssrComponent.spec.ts
+++ b/packages/compiler-ssr/__tests__/ssrComponent.spec.ts
@@ -57,13 +57,25 @@ describe('ssr: components', () => {
``,
).code,
).toMatchInlineSnapshot(`
- "const { resolveDynamicComponent: _resolveDynamicComponent, mergeProps: _mergeProps, createVNode: _createVNode } = require("vue")
- const { ssrRenderVNode: _ssrRenderVNode } = require("vue/server-renderer")
+ "const { resolveDynamicComponent: _resolveDynamicComponent, mergeProps: _mergeProps, createVNode: _createVNode } = require("vue")
+ const { ssrRenderVNode: _ssrRenderVNode } = require("vue/server-renderer")
- return function ssrRender(_ctx, _push, _parent, _attrs) {
- _ssrRenderVNode(_push, _createVNode(_resolveDynamicComponent("div"), _mergeProps({ innerHTML: '
ssr dynamic component v-html
' }, _attrs), null), _parent)
- }"
- `)
+ return function ssrRender(_ctx, _push, _parent, _attrs) {
+ _ssrRenderVNode(_push, _createVNode(_resolveDynamicComponent("div"), _mergeProps({ innerHTML: 'ssr dynamic component v-html
' }, _attrs), null), _parent)
+ }"
+ `)
+
+ expect(
+ compile(``)
+ .code,
+ ).toMatchInlineSnapshot(`
+ "const { resolveDynamicComponent: _resolveDynamicComponent, mergeProps: _mergeProps, createVNode: _createVNode } = require("vue")
+ const { ssrRenderVNode: _ssrRenderVNode } = require("vue/server-renderer")
+
+ return function ssrRender(_ctx, _push, _parent, _attrs) {
+ _ssrRenderVNode(_push, _createVNode(_resolveDynamicComponent("div"), _mergeProps({ textContent: 'ssr dynamic component v-text' }, _attrs), null), _parent)
+ }"
+ `)
})
describe('slots', () => {
diff --git a/packages/compiler-ssr/src/index.ts b/packages/compiler-ssr/src/index.ts
index 2c7ec97e5..d7fb043b9 100644
--- a/packages/compiler-ssr/src/index.ts
+++ b/packages/compiler-ssr/src/index.ts
@@ -28,6 +28,7 @@ import { ssrTransformShow } from './transforms/ssrVShow'
import { ssrInjectFallthroughAttrs } from './transforms/ssrInjectFallthroughAttrs'
import { ssrInjectCssVars } from './transforms/ssrInjectCssVars'
import { ssrTransformHtml } from './transforms/ssrVHtml'
+import { ssrTransformText } from './transforms/ssrVText'
export function compile(
source: string | RootNode,
@@ -73,9 +74,10 @@ export function compile(
// reusing core v-bind
bind: transformBind,
on: transformOn,
- // model, show and html have dedicated SSR handling
+ // model, show, text and html have dedicated SSR handling
model: ssrTransformModel,
show: ssrTransformShow,
+ text: ssrTransformText,
html: ssrTransformHtml,
// the following are ignored during SSR
// on: noopDirectiveTransform,
diff --git a/packages/compiler-ssr/src/transforms/ssrVText.ts b/packages/compiler-ssr/src/transforms/ssrVText.ts
new file mode 100644
index 000000000..81c3ebee7
--- /dev/null
+++ b/packages/compiler-ssr/src/transforms/ssrVText.ts
@@ -0,0 +1,37 @@
+import {
+ type DirectiveTransform,
+ ElementTypes,
+ TO_DISPLAY_STRING,
+ createCallExpression,
+ createObjectProperty,
+ createSimpleExpression,
+ getConstantType,
+} from '@vue/compiler-core'
+
+export const ssrTransformText: DirectiveTransform = (dir, node, context) => {
+ const { exp, loc } = dir
+
+ if (node.tagType !== ElementTypes.COMPONENT || node.tag !== 'component')
+ return { props: [] }
+
+ if (node.children.length) {
+ node.children.length = 0
+ }
+
+ return {
+ props: [
+ createObjectProperty(
+ createSimpleExpression(`textContent`, true),
+ exp
+ ? getConstantType(exp, context) > 0
+ ? exp
+ : createCallExpression(
+ context.helperString(TO_DISPLAY_STRING),
+ [exp],
+ loc,
+ )
+ : createSimpleExpression('', true),
+ ),
+ ],
+ }
+}