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\`"`)
|
expect(getCompiledString(`foo`)).toMatchInlineSnapshot(`"\`foo\`"`)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('comments', () => {
|
||||||
|
expect(getCompiledString(`<!--bar-->`)).toMatchInlineSnapshot(
|
||||||
|
`"\`<!--bar-->\`"`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
test('static text escape', () => {
|
test('static text escape', () => {
|
||||||
expect(getCompiledString(`<foo>`)).toMatchInlineSnapshot(
|
expect(getCompiledString(`<foo>`)).toMatchInlineSnapshot(
|
||||||
`"\`<foo>\`"`
|
`"\`<foo>\`"`
|
||||||
|
@ -19,11 +19,13 @@ export function createSSRCompilerError(
|
|||||||
export const enum SSRErrorCodes {
|
export const enum SSRErrorCodes {
|
||||||
X_SSR_CUSTOM_DIRECTIVE_NO_TRANSFORM = DOMErrorCodes.__EXTEND_POINT__,
|
X_SSR_CUSTOM_DIRECTIVE_NO_TRANSFORM = DOMErrorCodes.__EXTEND_POINT__,
|
||||||
X_SSR_UNSAFE_ATTR_NAME,
|
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 } = {
|
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_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_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 { ssrProcessSlotOutlet } from './transforms/ssrTransformSlotOutlet'
|
||||||
import { ssrProcessComponent } from './transforms/ssrTransformComponent'
|
import { ssrProcessComponent } from './transforms/ssrTransformComponent'
|
||||||
import { ssrProcessElement } from './transforms/ssrTransformElement'
|
import { ssrProcessElement } from './transforms/ssrTransformElement'
|
||||||
|
import { createSSRCompilerError, SSRErrorCodes } from './errors'
|
||||||
|
|
||||||
// Because SSR codegen output is completely different from client-side output
|
// Because SSR codegen output is completely different from client-side output
|
||||||
// (e.g. multiple elements can be concatenated into a single template literal
|
// (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++) {
|
for (let i = 0; i < children.length; i++) {
|
||||||
const child = children[i]
|
const child = children[i]
|
||||||
if (child.type === NodeTypes.ELEMENT) {
|
switch (child.type) {
|
||||||
if (child.tagType === ElementTypes.ELEMENT) {
|
case NodeTypes.ELEMENT:
|
||||||
ssrProcessElement(child, context)
|
switch (child.tagType) {
|
||||||
} else if (child.tagType === ElementTypes.COMPONENT) {
|
case ElementTypes.ELEMENT:
|
||||||
ssrProcessComponent(child, context)
|
ssrProcessElement(child, context)
|
||||||
} else if (child.tagType === ElementTypes.SLOT) {
|
break
|
||||||
ssrProcessSlotOutlet(child, context)
|
case ElementTypes.COMPONENT:
|
||||||
}
|
ssrProcessComponent(child, context)
|
||||||
} else if (child.type === NodeTypes.TEXT) {
|
break
|
||||||
context.pushStringPart(escapeHtml(child.content))
|
case ElementTypes.SLOT:
|
||||||
} else if (child.type === NodeTypes.INTERPOLATION) {
|
ssrProcessSlotOutlet(child, context)
|
||||||
context.pushStringPart(
|
break
|
||||||
createCallExpression(context.helper(SSR_INTERPOLATE), [child.content])
|
case ElementTypes.TEMPLATE:
|
||||||
)
|
// TODO
|
||||||
} else if (child.type === NodeTypes.IF) {
|
break
|
||||||
ssrProcessIf(child, context)
|
default:
|
||||||
} else if (child.type === NodeTypes.FOR) {
|
context.onError(
|
||||||
ssrProcessFor(child, context)
|
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) {
|
if (asFragment) {
|
||||||
|
@ -27,7 +27,8 @@ import {
|
|||||||
isVoidTag,
|
isVoidTag,
|
||||||
escapeHtml,
|
escapeHtml,
|
||||||
NO,
|
NO,
|
||||||
generateCodeFrame
|
generateCodeFrame,
|
||||||
|
escapeHtmlComment
|
||||||
} from '@vue/shared'
|
} from '@vue/shared'
|
||||||
import { compile } from '@vue/compiler-ssr'
|
import { compile } from '@vue/compiler-ssr'
|
||||||
import { ssrRenderAttrs } from './helpers/ssrRenderAttrs'
|
import { ssrRenderAttrs } from './helpers/ssrRenderAttrs'
|
||||||
@ -230,9 +231,6 @@ function ssrCompile(
|
|||||||
return (compileCache[template] = Function('require', code)(require))
|
return (compileCache[template] = Function('require', code)(require))
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://www.w3.org/TR/html52/syntax.html#comments
|
|
||||||
const commentStripRE = /^-?>|<!--|-->|--!>|<!-$/g
|
|
||||||
|
|
||||||
function renderVNode(
|
function renderVNode(
|
||||||
push: PushFn,
|
push: PushFn,
|
||||||
vnode: VNode,
|
vnode: VNode,
|
||||||
@ -245,9 +243,7 @@ function renderVNode(
|
|||||||
break
|
break
|
||||||
case Comment:
|
case Comment:
|
||||||
push(
|
push(
|
||||||
children
|
children ? `<!--${escapeHtmlComment(children as string)}-->` : `<!---->`
|
||||||
? `<!--${(children as string).replace(commentStripRE, '')}-->`
|
|
||||||
: `<!---->`
|
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
case Static:
|
case Static:
|
||||||
|
@ -43,3 +43,10 @@ export function escapeHtml(string: unknown) {
|
|||||||
|
|
||||||
return lastIndex !== index ? html + str.substring(lastIndex, index) : html
|
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