wip(ssr): basic components

This commit is contained in:
Evan You
2020-02-05 23:07:23 -05:00
parent 27e2e482e9
commit ee5ed73361
20 changed files with 254 additions and 132 deletions

View File

@@ -0,0 +1,48 @@
import { compile } from '../src'
describe('ssr: components', () => {
test('basic', () => {
expect(compile(`<foo id="a" :prop="b" />`).code).toMatchInlineSnapshot(`
"const { resolveComponent } = require(\\"vue\\")
const { _renderComponent } = require(\\"@vue/server-renderer\\")
return function ssrRender(_ctx, _push, _parent) {
const _component_foo = resolveComponent(\\"foo\\")
_renderComponent(_component_foo, {
id: \\"a\\",
prop: _ctx.b
}, null, _parent)
}"
`)
})
test('dynamic component', () => {
expect(compile(`<component is="foo" prop="b" />`).code)
.toMatchInlineSnapshot(`
"const { resolveComponent } = require(\\"vue\\")
const { _renderComponent } = require(\\"@vue/server-renderer\\")
return function ssrRender(_ctx, _push, _parent) {
const _component_foo = resolveComponent(\\"foo\\")
_renderComponent(_component_foo, { prop: \\"b\\" }, null, _parent)
}"
`)
expect(compile(`<compoonent :is="foo" prop="b" />`).code)
.toMatchInlineSnapshot(`
"const { resolveComponent } = require(\\"vue\\")
const { _renderComponent } = require(\\"@vue/server-renderer\\")
return function ssrRender(_ctx, _push, _parent) {
const _component_compoonent = resolveComponent(\\"compoonent\\")
_renderComponent(_component_compoonent, {
is: _ctx.foo,
prop: \\"b\\"
}, null, _parent)
}"
`)
})
})

View File

@@ -18,6 +18,7 @@ import { SSR_INTERPOLATE, ssrHelpers } from './runtimeHelpers'
import { ssrProcessIf } from './transforms/ssrVIf'
import { ssrProcessFor } from './transforms/ssrVFor'
import { ssrProcessSlotOutlet } from './transforms/ssrTransformSlotOutlet'
import { ssrProcessComponent } from './transforms/ssrTransformComponent'
// Because SSR codegen output is completely different from client-side output
// (e.g. multiple elements can be concatenated into a single template literal
@@ -118,7 +119,7 @@ export function processChildren(
context.pushStringPart(`</${child.tag}>`)
}
} else if (child.tagType === ElementTypes.COMPONENT) {
// TODO
ssrProcessComponent(child, context)
} else if (child.tagType === ElementTypes.SLOT) {
ssrProcessSlotOutlet(child, context)
}

View File

@@ -1,15 +1,64 @@
import { NodeTransform, NodeTypes, ElementTypes } from '@vue/compiler-dom'
import {
NodeTransform,
NodeTypes,
ElementTypes,
createCallExpression,
resolveComponentType,
buildProps,
ComponentNode,
PORTAL,
SUSPENSE
} from '@vue/compiler-dom'
import { SSR_RENDER_COMPONENT } from '../runtimeHelpers'
import { SSRTransformContext } from '../ssrCodegenTransform'
import { isSymbol } from '@vue/shared'
export const ssrTransformComponent: NodeTransform = (node, context) => {
if (
node.type === NodeTypes.ELEMENT &&
node.tagType === ElementTypes.COMPONENT
node.type !== NodeTypes.ELEMENT ||
node.tagType !== ElementTypes.COMPONENT
) {
return function ssrPostTransformComponent() {
// generate a _push(_renderComponent) call
// dynamic component as well
// !check if we need to bail out for slots
// TODO also handle scopeID here
return
}
return function ssrPostTransformComponent() {
const component = resolveComponentType(node, context)
if (isSymbol(component)) {
// built-in compoonent
if (component === PORTAL) {
// TODO
} else if (component === SUSPENSE) {
// TODO fallthrough
// TODO option to use fallback content and resolve on client
} else {
// TODO fallthrough for KeepAlive & Transition
}
}
// note we are not passing ssr: true here because for components, v-on
// handlers should still be passed
const { props } = buildProps(node, context)
// TODO slots
// TODO option for slots bail out
// TODO scopeId
node.ssrCodegenNode = createCallExpression(
context.helper(SSR_RENDER_COMPONENT),
[
component,
props || `null`,
`null`, // TODO slots
`_parent`
]
)
}
}
export function ssrProcessComponent(
node: ComponentNode,
context: SSRTransformContext
) {
context.pushStatement(node.ssrCodegenNode!)
}

View File

@@ -21,7 +21,8 @@ import {
createAssignmentExpression,
TextNode,
hasDynamicKeyVBind,
MERGE_PROPS
MERGE_PROPS,
isBindKey
} from '@vue/compiler-dom'
import { escapeHtml, isBooleanAttr, isSSRSafeAttrName } from '@vue/shared'
import { createSSRCompilerError, SSRErrorCodes } from '../errors'
@@ -261,10 +262,7 @@ function isTextareaWithValue(
return !!(
node.tag === 'textarea' &&
prop.name === 'bind' &&
prop.arg &&
prop.arg.type === NodeTypes.SIMPLE_EXPRESSION &&
prop.arg.isStatic &&
prop.arg.content === 'value'
isBindKey(prop.arg, 'value')
)
}