test(ssr): test for rendering components
This commit is contained in:
parent
6e06810add
commit
8cdaf28515
@ -64,7 +64,12 @@ export interface ComponentOptionsBase<
|
||||
// type.
|
||||
render?: Function
|
||||
// SSR only. This is produced by compiler-ssr and attached in compiler-sfc
|
||||
ssrRender?: Function
|
||||
// not user facing, so the typing is lax and for test only.
|
||||
ssrRender?: (
|
||||
ctx: any,
|
||||
push: (item: any) => void,
|
||||
parentInstance: ComponentInternalInstance
|
||||
) => void
|
||||
components?: Record<
|
||||
string,
|
||||
Component | { new (): ComponentPublicInstance<any, any, any, any, any> }
|
||||
|
@ -1,7 +1,261 @@
|
||||
// import { renderToString, renderComponent } from '../src'
|
||||
import { createApp, h } from 'vue'
|
||||
import { renderToString, renderComponent, renderSlot } from '../src'
|
||||
|
||||
describe('ssr: renderToString', () => {
|
||||
describe('elements', () => {
|
||||
describe('components', () => {
|
||||
test('vnode components', async () => {
|
||||
expect(
|
||||
await renderToString(
|
||||
createApp({
|
||||
data() {
|
||||
return { msg: 'hello' }
|
||||
},
|
||||
render(this: any) {
|
||||
return h('div', this.msg)
|
||||
}
|
||||
})
|
||||
)
|
||||
).toBe(`<div>hello</div>`)
|
||||
})
|
||||
|
||||
test('optimized components', async () => {
|
||||
expect(
|
||||
await renderToString(
|
||||
createApp({
|
||||
data() {
|
||||
return { msg: 'hello' }
|
||||
},
|
||||
ssrRender(ctx, push) {
|
||||
push(`<div>${ctx.msg}</div>`)
|
||||
}
|
||||
})
|
||||
)
|
||||
).toBe(`<div>hello</div>`)
|
||||
})
|
||||
|
||||
test('nested vnode components', async () => {
|
||||
const Child = {
|
||||
props: ['msg'],
|
||||
render(this: any) {
|
||||
return h('div', this.msg)
|
||||
}
|
||||
}
|
||||
|
||||
expect(
|
||||
await renderToString(
|
||||
createApp({
|
||||
render() {
|
||||
return h('div', ['parent', h(Child, { msg: 'hello' })])
|
||||
}
|
||||
})
|
||||
)
|
||||
).toBe(`<div>parent<div>hello</div></div>`)
|
||||
})
|
||||
|
||||
test('nested optimized components', async () => {
|
||||
const Child = {
|
||||
props: ['msg'],
|
||||
ssrRender(ctx: any, push: any) {
|
||||
push(`<div>${ctx.msg}</div>`)
|
||||
}
|
||||
}
|
||||
|
||||
expect(
|
||||
await renderToString(
|
||||
createApp({
|
||||
ssrRender(_ctx, push, parent) {
|
||||
push(`<div>parent`)
|
||||
push(renderComponent(Child, { msg: 'hello' }, null, parent))
|
||||
push(`</div>`)
|
||||
}
|
||||
})
|
||||
)
|
||||
).toBe(`<div>parent<div>hello</div></div>`)
|
||||
})
|
||||
|
||||
test('mixing optimized / vnode components', async () => {
|
||||
const OptimizedChild = {
|
||||
props: ['msg'],
|
||||
ssrRender(ctx: any, push: any) {
|
||||
push(`<div>${ctx.msg}</div>`)
|
||||
}
|
||||
}
|
||||
|
||||
const VNodeChild = {
|
||||
props: ['msg'],
|
||||
render(this: any) {
|
||||
return h('div', this.msg)
|
||||
}
|
||||
}
|
||||
|
||||
expect(
|
||||
await renderToString(
|
||||
createApp({
|
||||
ssrRender(_ctx, push, parent) {
|
||||
push(`<div>parent`)
|
||||
push(
|
||||
renderComponent(OptimizedChild, { msg: 'opt' }, null, parent)
|
||||
)
|
||||
push(renderComponent(VNodeChild, { msg: 'vnode' }, null, parent))
|
||||
push(`</div>`)
|
||||
}
|
||||
})
|
||||
)
|
||||
).toBe(`<div>parent<div>opt</div><div>vnode</div></div>`)
|
||||
})
|
||||
|
||||
test('nested components with optimized slots', async () => {
|
||||
const Child = {
|
||||
props: ['msg'],
|
||||
ssrRender(ctx: any, push: any, parent: any) {
|
||||
push(`<div class="child">`)
|
||||
renderSlot(ctx.$slots.default, { msg: 'from slot' }, push, parent)
|
||||
push(`</div>`)
|
||||
}
|
||||
}
|
||||
|
||||
expect(
|
||||
await renderToString(
|
||||
createApp({
|
||||
ssrRender(_ctx, push, parent) {
|
||||
push(`<div>parent`)
|
||||
push(
|
||||
renderComponent(
|
||||
Child,
|
||||
{ msg: 'hello' },
|
||||
{
|
||||
// optimized slot using string push
|
||||
default: ({ msg }: any, push: any) => {
|
||||
push(`<span>${msg}</span>`)
|
||||
},
|
||||
_compiled: true // important to avoid slots being normalized
|
||||
},
|
||||
parent
|
||||
)
|
||||
)
|
||||
push(`</div>`)
|
||||
}
|
||||
})
|
||||
)
|
||||
).toBe(
|
||||
`<div>parent<div class="child">` +
|
||||
`<!----><span>from slot</span><!---->` +
|
||||
`</div></div>`
|
||||
)
|
||||
})
|
||||
|
||||
test('nested components with vnode slots', async () => {
|
||||
const Child = {
|
||||
props: ['msg'],
|
||||
ssrRender(ctx: any, push: any, parent: any) {
|
||||
push(`<div class="child">`)
|
||||
renderSlot(ctx.$slots.default, { msg: 'from slot' }, push, parent)
|
||||
push(`</div>`)
|
||||
}
|
||||
}
|
||||
|
||||
expect(
|
||||
await renderToString(
|
||||
createApp({
|
||||
ssrRender(_ctx, push, parent) {
|
||||
push(`<div>parent`)
|
||||
push(
|
||||
renderComponent(
|
||||
Child,
|
||||
{ msg: 'hello' },
|
||||
{
|
||||
// bailed slots returning raw vnodes
|
||||
default: ({ msg }: any) => {
|
||||
return h('span', msg)
|
||||
}
|
||||
},
|
||||
parent
|
||||
)
|
||||
)
|
||||
push(`</div>`)
|
||||
}
|
||||
})
|
||||
)
|
||||
).toBe(
|
||||
`<div>parent<div class="child">` +
|
||||
`<!----><span>from slot</span><!---->` +
|
||||
`</div></div>`
|
||||
)
|
||||
})
|
||||
|
||||
test('async components', async () => {
|
||||
const Child = {
|
||||
// should wait for resovled render context from setup()
|
||||
async setup() {
|
||||
return {
|
||||
msg: 'hello'
|
||||
}
|
||||
},
|
||||
ssrRender(ctx: any, push: any) {
|
||||
push(`<div>${ctx.msg}</div>`)
|
||||
}
|
||||
}
|
||||
|
||||
expect(
|
||||
await renderToString(
|
||||
createApp({
|
||||
ssrRender(_ctx, push, parent) {
|
||||
push(`<div>parent`)
|
||||
push(renderComponent(Child, null, null, parent))
|
||||
push(`</div>`)
|
||||
}
|
||||
})
|
||||
)
|
||||
).toBe(`<div>parent<div>hello</div></div>`)
|
||||
})
|
||||
|
||||
test('parallel async components', async () => {
|
||||
const OptimizedChild = {
|
||||
props: ['msg'],
|
||||
async setup(props: any) {
|
||||
return {
|
||||
localMsg: props.msg + '!'
|
||||
}
|
||||
},
|
||||
ssrRender(ctx: any, push: any) {
|
||||
push(`<div>${ctx.localMsg}</div>`)
|
||||
}
|
||||
}
|
||||
|
||||
const VNodeChild = {
|
||||
props: ['msg'],
|
||||
async setup(props: any) {
|
||||
return {
|
||||
localMsg: props.msg + '!'
|
||||
}
|
||||
},
|
||||
render(this: any) {
|
||||
return h('div', this.localMsg)
|
||||
}
|
||||
}
|
||||
|
||||
expect(
|
||||
await renderToString(
|
||||
createApp({
|
||||
ssrRender(_ctx, push, parent) {
|
||||
push(`<div>parent`)
|
||||
push(
|
||||
renderComponent(OptimizedChild, { msg: 'opt' }, null, parent)
|
||||
)
|
||||
push(renderComponent(VNodeChild, { msg: 'vnode' }, null, parent))
|
||||
push(`</div>`)
|
||||
}
|
||||
})
|
||||
)
|
||||
).toBe(`<div>parent<div>opt!</div><div>vnode!</div></div>`)
|
||||
})
|
||||
})
|
||||
|
||||
describe('scopeId', () => {
|
||||
// TODO
|
||||
})
|
||||
|
||||
describe('vnode', () => {
|
||||
test('text children', () => {})
|
||||
|
||||
test('array children', () => {})
|
||||
@ -14,18 +268,4 @@ describe('ssr: renderToString', () => {
|
||||
|
||||
test('textarea value', () => {})
|
||||
})
|
||||
|
||||
describe('components', () => {
|
||||
test('nested components', () => {})
|
||||
|
||||
test('nested components with optimized slots', () => {})
|
||||
|
||||
test('mixing optimized / vnode components', () => {})
|
||||
|
||||
test('nested components with vnode slots', () => {})
|
||||
|
||||
test('async components', () => {})
|
||||
|
||||
test('parallel async components', () => {})
|
||||
})
|
||||
})
|
||||
|
@ -125,7 +125,7 @@ function renderComponentSubTree(
|
||||
} else {
|
||||
if (comp.ssrRender) {
|
||||
// optimized
|
||||
comp.ssrRender(push, instance.proxy)
|
||||
comp.ssrRender(instance.proxy, push, instance)
|
||||
} else if (comp.render) {
|
||||
renderVNode(push, renderComponentRoot(instance), instance)
|
||||
} else {
|
||||
@ -260,8 +260,8 @@ export function renderSlot(
|
||||
) {
|
||||
// template-compiled slots are always rendered as fragments
|
||||
push(`<!---->`)
|
||||
if (slotFn.length > 2) {
|
||||
// only ssr-optimized slot fns accept 3 arguments
|
||||
if (slotFn.length > 1) {
|
||||
// only ssr-optimized slot fns accept more than 1 arguments
|
||||
slotFn(slotProps, push, parentComponent)
|
||||
} else {
|
||||
// normal slot
|
||||
|
@ -20,7 +20,8 @@
|
||||
"types": ["jest", "puppeteer", "node"],
|
||||
"rootDir": ".",
|
||||
"paths": {
|
||||
"@vue/*": ["packages/*/src"]
|
||||
"@vue/*": ["packages/*/src"],
|
||||
"vue": ["packages/vue/src"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
|
Loading…
Reference in New Issue
Block a user