|
|
@@ -24,7 +24,7 @@ import {
|
|
|
MERGE_PROPS,
|
|
|
isBindKey
|
|
|
} from '@vue/compiler-dom'
|
|
|
-import { escapeHtml, isBooleanAttr, isSSRSafeAttrName } from '@vue/shared'
|
|
|
+import { escapeHtml, isBooleanAttr, isSSRSafeAttrName, NO } from '@vue/shared'
|
|
|
import { createSSRCompilerError, SSRErrorCodes } from '../errors'
|
|
|
import {
|
|
|
SSR_RENDER_ATTR,
|
|
|
@@ -35,6 +35,14 @@ import {
|
|
|
SSR_INTERPOLATE,
|
|
|
SSR_GET_DYNAMIC_MODEL_PROPS
|
|
|
} from '../runtimeHelpers'
|
|
|
+import { SSRTransformContext, processChildren } from '../ssrCodegenTransform'
|
|
|
+
|
|
|
+// for directives with children overwrite (e.g. v-html & v-text), we need to
|
|
|
+// store the raw children so that they can be added in the 2nd pass.
|
|
|
+const rawChildrenMap = new WeakMap<
|
|
|
+ PlainElementNode,
|
|
|
+ TemplateLiteral['elements'][0]
|
|
|
+>()
|
|
|
|
|
|
export const ssrTransformElement: NodeTransform = (node, context) => {
|
|
|
if (
|
|
|
@@ -45,7 +53,6 @@ export const ssrTransformElement: NodeTransform = (node, context) => {
|
|
|
// element
|
|
|
// generate the template literal representing the open tag.
|
|
|
const openTag: TemplateLiteral['elements'] = [`<${node.tag}`]
|
|
|
- let rawChildren
|
|
|
|
|
|
// v-bind="obj" or v-bind:[key] can potentially overwrite other static
|
|
|
// attrs and can affect final rendering result, so when they are present
|
|
|
@@ -70,10 +77,9 @@ export const ssrTransformElement: NodeTransform = (node, context) => {
|
|
|
props
|
|
|
)
|
|
|
const existingText = node.children[0] as TextNode | undefined
|
|
|
- node.children = []
|
|
|
- rawChildren = createCallExpression(
|
|
|
- context.helper(SSR_INTERPOLATE),
|
|
|
- [
|
|
|
+ rawChildrenMap.set(
|
|
|
+ node,
|
|
|
+ createCallExpression(context.helper(SSR_INTERPOLATE), [
|
|
|
createConditionalExpression(
|
|
|
createSimpleExpression(`"value" in ${tempId}`, false),
|
|
|
createSimpleExpression(`${tempId}.value`, false),
|
|
|
@@ -83,7 +89,7 @@ export const ssrTransformElement: NodeTransform = (node, context) => {
|
|
|
),
|
|
|
false
|
|
|
)
|
|
|
- ]
|
|
|
+ ])
|
|
|
)
|
|
|
} else if (node.tag === 'input') {
|
|
|
// <input v-bind="obj" v-model>
|
|
|
@@ -126,8 +132,7 @@ export const ssrTransformElement: NodeTransform = (node, context) => {
|
|
|
// special cases with children override
|
|
|
if (prop.type === NodeTypes.DIRECTIVE) {
|
|
|
if (prop.name === 'html' && prop.exp) {
|
|
|
- node.children = []
|
|
|
- rawChildren = prop.exp
|
|
|
+ rawChildrenMap.set(node, prop.exp)
|
|
|
} else if (prop.name === 'text' && prop.exp) {
|
|
|
node.children = [createInterpolation(prop.exp, prop.loc)]
|
|
|
} else if (prop.name === 'slot') {
|
|
|
@@ -225,8 +230,7 @@ export const ssrTransformElement: NodeTransform = (node, context) => {
|
|
|
} else {
|
|
|
// special case: value on <textarea>
|
|
|
if (node.tag === 'textarea' && prop.name === 'value' && prop.value) {
|
|
|
- node.children = []
|
|
|
- rawChildren = escapeHtml(prop.value.content)
|
|
|
+ rawChildrenMap.set(node, escapeHtml(prop.value.content))
|
|
|
} else if (!hasDynamicVBind) {
|
|
|
// static prop
|
|
|
if (prop.name === 'class' && prop.value) {
|
|
|
@@ -250,10 +254,6 @@ export const ssrTransformElement: NodeTransform = (node, context) => {
|
|
|
openTag.push(` ${context.scopeId}`)
|
|
|
}
|
|
|
|
|
|
- openTag.push(`>`)
|
|
|
- if (rawChildren) {
|
|
|
- openTag.push(rawChildren)
|
|
|
- }
|
|
|
node.ssrCodegenNode = createTemplateLiteral(openTag)
|
|
|
}
|
|
|
}
|
|
|
@@ -296,3 +296,35 @@ function findVModel(node: PlainElementNode): DirectiveNode | undefined {
|
|
|
p => p.type === NodeTypes.DIRECTIVE && p.name === 'model' && p.exp
|
|
|
) as DirectiveNode | undefined
|
|
|
}
|
|
|
+
|
|
|
+export function ssrProcessElement(
|
|
|
+ node: PlainElementNode,
|
|
|
+ context: SSRTransformContext
|
|
|
+) {
|
|
|
+ const isVoidTag = context.options.isVoidTag || NO
|
|
|
+ const elementsToAdd = node.ssrCodegenNode!.elements
|
|
|
+ for (let j = 0; j < elementsToAdd.length; j++) {
|
|
|
+ context.pushStringPart(elementsToAdd[j])
|
|
|
+ }
|
|
|
+
|
|
|
+ // Handle slot scopeId
|
|
|
+ if (context.withSlotScopeId) {
|
|
|
+ context.pushStringPart(` `)
|
|
|
+ context.pushStringPart(createSimpleExpression(`_scopeId`, false))
|
|
|
+ }
|
|
|
+
|
|
|
+ // close open tag
|
|
|
+ context.pushStringPart(`>`)
|
|
|
+
|
|
|
+ const rawChildren = rawChildrenMap.get(node)
|
|
|
+ if (rawChildren) {
|
|
|
+ context.pushStringPart(rawChildren)
|
|
|
+ } else if (node.children.length) {
|
|
|
+ processChildren(node.children, context)
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!isVoidTag(node.tag)) {
|
|
|
+ // push closing tag
|
|
|
+ context.pushStringPart(`</${node.tag}>`)
|
|
|
+ }
|
|
|
+}
|