fix(compiler-ssr): handle comments codegen + refactor ssr codegen transform
This commit is contained in:
parent
0e730c06e4
commit
6c60ce13e0
@ -6,6 +6,12 @@ describe('ssr: text', () => {
|
||||
expect(getCompiledString(`foo`)).toMatchInlineSnapshot(`"\`foo\`"`)
|
||||
})
|
||||
|
||||
test('comments', () => {
|
||||
expect(getCompiledString(`<!--bar-->`)).toMatchInlineSnapshot(
|
||||
`"\`<!--bar-->\`"`
|
||||
)
|
||||
})
|
||||
|
||||
test('static text escape', () => {
|
||||
expect(getCompiledString(`<foo>`)).toMatchInlineSnapshot(
|
||||
`"\`<foo>\`"`
|
||||
|
@ -19,11 +19,13 @@ export function createSSRCompilerError(
|
||||
export const enum SSRErrorCodes {
|
||||
X_SSR_CUSTOM_DIRECTIVE_NO_TRANSFORM = DOMErrorCodes.__EXTEND_POINT__,
|
||||
X_SSR_UNSAFE_ATTR_NAME,
|
||||
X_SSR_NO_TELEPORT_TARGET
|
||||
X_SSR_NO_TELEPORT_TARGET,
|
||||
X_SSR_INVALID_AST_NODE
|
||||
}
|
||||
|
||||
export const SSRErrorMessages: { [code: number]: string } = {
|
||||
[SSRErrorCodes.X_SSR_CUSTOM_DIRECTIVE_NO_TRANSFORM]: `Custom directive is missing corresponding SSR transform and will be ignored.`,
|
||||
[SSRErrorCodes.X_SSR_UNSAFE_ATTR_NAME]: `Unsafe attribute name for SSR.`,
|
||||
[SSRErrorCodes.X_SSR_NO_TELEPORT_TARGET]: `No target prop on teleport element.`
|
||||
[SSRErrorCodes.X_SSR_NO_TELEPORT_TARGET]: `No target prop on teleport element.`,
|
||||
[SSRErrorCodes.X_SSR_INVALID_AST_NODE]: `Invalid AST node during ssr transform`
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import { ssrProcessFor } from './transforms/ssrVFor'
|
||||
import { ssrProcessSlotOutlet } from './transforms/ssrTransformSlotOutlet'
|
||||
import { ssrProcessComponent } from './transforms/ssrTransformComponent'
|
||||
import { ssrProcessElement } from './transforms/ssrTransformElement'
|
||||
import { createSSRCompilerError, SSRErrorCodes } from './errors'
|
||||
|
||||
// Because SSR codegen output is completely different from client-side output
|
||||
// (e.g. multiple elements can be concatenated into a single template literal
|
||||
@ -115,24 +116,70 @@ export function processChildren(
|
||||
}
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
const child = children[i]
|
||||
if (child.type === NodeTypes.ELEMENT) {
|
||||
if (child.tagType === ElementTypes.ELEMENT) {
|
||||
ssrProcessElement(child, context)
|
||||
} else if (child.tagType === ElementTypes.COMPONENT) {
|
||||
ssrProcessComponent(child, context)
|
||||
} else if (child.tagType === ElementTypes.SLOT) {
|
||||
ssrProcessSlotOutlet(child, context)
|
||||
}
|
||||
} else if (child.type === NodeTypes.TEXT) {
|
||||
context.pushStringPart(escapeHtml(child.content))
|
||||
} else if (child.type === NodeTypes.INTERPOLATION) {
|
||||
context.pushStringPart(
|
||||
createCallExpression(context.helper(SSR_INTERPOLATE), [child.content])
|
||||
)
|
||||
} else if (child.type === NodeTypes.IF) {
|
||||
ssrProcessIf(child, context)
|
||||
} else if (child.type === NodeTypes.FOR) {
|
||||
ssrProcessFor(child, context)
|
||||
switch (child.type) {
|
||||
case NodeTypes.ELEMENT:
|
||||
switch (child.tagType) {
|
||||
case ElementTypes.ELEMENT:
|
||||
ssrProcessElement(child, context)
|
||||
break
|
||||
case ElementTypes.COMPONENT:
|
||||
ssrProcessComponent(child, context)
|
||||
break
|
||||
case ElementTypes.SLOT:
|
||||
ssrProcessSlotOutlet(child, context)
|
||||
break
|
||||
case ElementTypes.TEMPLATE:
|
||||
// TODO
|
||||
break
|
||||
default:
|
||||
context.onError(
|
||||
createSSRCompilerError(
|
||||
SSRErrorCodes.X_SSR_INVALID_AST_NODE,
|
||||
(child as any).loc
|
||||
)
|
||||
)
|
||||
// make sure we exhaust all possible types
|
||||
const exhaustiveCheck: never = child
|
||||
return exhaustiveCheck
|
||||
}
|
||||
break
|
||||
case NodeTypes.TEXT:
|
||||
context.pushStringPart(escapeHtml(child.content))
|
||||
break
|
||||
case NodeTypes.COMMENT:
|
||||
// no need to escape comment here because the AST can only
|
||||
// contain valid comments.
|
||||
context.pushStringPart(`<!--${child.content}-->`)
|
||||
break
|
||||
case NodeTypes.INTERPOLATION:
|
||||
context.pushStringPart(
|
||||
createCallExpression(context.helper(SSR_INTERPOLATE), [child.content])
|
||||
)
|
||||
break
|
||||
case NodeTypes.IF:
|
||||
ssrProcessIf(child, context)
|
||||
break
|
||||
case NodeTypes.FOR:
|
||||
ssrProcessFor(child, context)
|
||||
break
|
||||
case NodeTypes.IF_BRANCH:
|
||||
// no-op - handled by ssrProcessIf
|
||||
break
|
||||
case NodeTypes.TEXT_CALL:
|
||||
case NodeTypes.COMPOUND_EXPRESSION:
|
||||
// no-op - these two types can never appear as template child node since
|
||||
// `transformText` is not used during SSR compile.
|
||||
break
|
||||
default:
|
||||
context.onError(
|
||||
createSSRCompilerError(
|
||||
SSRErrorCodes.X_SSR_INVALID_AST_NODE,
|
||||
(child as any).loc
|
||||
)
|
||||
)
|
||||
// make sure we exhaust all possible types
|
||||
const exhaustiveCheck: never = child
|
||||
return exhaustiveCheck
|
||||
}
|
||||
}
|
||||
if (asFragment) {
|
||||
|
@ -27,7 +27,8 @@ import {
|
||||
isVoidTag,
|
||||
escapeHtml,
|
||||
NO,
|
||||
generateCodeFrame
|
||||
generateCodeFrame,
|
||||
escapeHtmlComment
|
||||
} from '@vue/shared'
|
||||
import { compile } from '@vue/compiler-ssr'
|
||||
import { ssrRenderAttrs } from './helpers/ssrRenderAttrs'
|
||||
@ -230,9 +231,6 @@ function ssrCompile(
|
||||
return (compileCache[template] = Function('require', code)(require))
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/html52/syntax.html#comments
|
||||
const commentStripRE = /^-?>|<!--|-->|--!>|<!-$/g
|
||||
|
||||
function renderVNode(
|
||||
push: PushFn,
|
||||
vnode: VNode,
|
||||
@ -245,9 +243,7 @@ function renderVNode(
|
||||
break
|
||||
case Comment:
|
||||
push(
|
||||
children
|
||||
? `<!--${(children as string).replace(commentStripRE, '')}-->`
|
||||
: `<!---->`
|
||||
children ? `<!--${escapeHtmlComment(children as string)}-->` : `<!---->`
|
||||
)
|
||||
break
|
||||
case Static:
|
||||
|
@ -43,3 +43,10 @@ export function escapeHtml(string: unknown) {
|
||||
|
||||
return lastIndex !== index ? html + str.substring(lastIndex, index) : html
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/html52/syntax.html#comments
|
||||
const commentStripRE = /^-?>|<!--|-->|--!>|<!-$/g
|
||||
|
||||
export function escapeHtmlComment(src: string): string {
|
||||
return src.replace(commentStripRE, '')
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user