Skip to content

Commit

Permalink
fix(ssr): fix SSR for async functional components
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 authored and hefeng committed Jan 25, 2019
1 parent 0d727c7 commit f191c1f
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 4 deletions.
7 changes: 6 additions & 1 deletion src/server/render-context.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,18 @@ export class RenderContext {
}
switch (lastState.type) {
case 'Element':
case 'Fragment':
const { children, total } = lastState
const rendered = lastState.rendered++
if (rendered < total) {
this.renderNode(children[rendered], false, this)
} else {
this.renderStates.pop()
this.write(lastState.endTag, this.next)
if (lastState.endTag) {
this.write(lastState.endTag, this.next)
} else {
this.next()
}
}
break
case 'Component':
Expand Down
22 changes: 19 additions & 3 deletions src/server/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,21 @@ function renderAsyncComponent (node, isRoot, context) {
tag
)
if (resolvedNode) {
renderComponent(resolvedNode, isRoot, context)
if (resolvedNode.componnetInstance) {
renderComponent(resolvedNode, isRoot, context)
} else if (!Array.isArray(resolvedNode)) {
// single return node from functional component
renderNode(resolvedNode, isRoot, context)
} else {
// multiple return nodes from functional component
context.renderStates.push({
type: 'Fragment',
children: resolvedNode,
rendered: 0,
total: resolvedNode.length
})
context.next()
}
} else {
// invalid component, but this does not throw on the client
// so render empty comment node
Expand Down Expand Up @@ -232,9 +246,10 @@ function renderStringNode (el, context) {
const children: Array<VNode> = el.children
context.renderStates.push({
type: 'Element',
children,
rendered: 0,
total: children.length,
endTag: el.close, children
endTag: el.close
})
write(el.open, next)
}
Expand Down Expand Up @@ -263,9 +278,10 @@ function renderElement (el, isRoot, context) {
const children: Array<VNode> = el.children
context.renderStates.push({
type: 'Element',
children,
rendered: 0,
total: children.length,
endTag, children
endTag
})
write(startTag, next)
}
Expand Down
54 changes: 54 additions & 0 deletions test/ssr/ssr-string.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,60 @@ describe('SSR: renderToString', () => {
})
})

it('renders async component (functional, single node)', done => {
renderVmWithOptions({
template: `
<div>
<test-async></test-async>
</div>
`,
components: {
testAsync (resolve) {
setTimeout(() => resolve({
functional: true,
render (h) {
return h('span', { class: ['b'] }, 'testAsync')
}
}), 1)
}
}
}, result => {
expect(result).toContain('<div data-server-rendered="true"><span class="b">testAsync</span></div>')
done()
})
})

it('renders async component (functional, multiple nodes)', done => {
renderVmWithOptions({
template: `
<div>
<test-async></test-async>
</div>
`,
components: {
testAsync (resolve) {
setTimeout(() => resolve({
functional: true,
render (h) {
return [
h('span', { class: ['a'] }, 'foo'),
h('span', { class: ['b'] }, 'bar')
]
}
}), 1)
}
}
}, result => {
expect(result).toContain(
'<div data-server-rendered="true">' +
'<span class="a">foo</span>' +
'<span class="b">bar</span>' +
'</div>'
)
done()
})
})

it('should catch async component error', done => {
Vue.config.silent = true
renderToString(new Vue({
Expand Down

0 comments on commit f191c1f

Please sign in to comment.