Skip to content

Commit

Permalink
feat: resolve ES module default when resolving async components
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Jun 29, 2017
1 parent b5f08f3 commit 0cd6ef3
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 58 deletions.
3 changes: 3 additions & 0 deletions src/core/vdom/helpers/resolve-async-component.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import {
import { createEmptyVNode } from 'core/vdom/vnode'

function ensureCtor (comp, base) {
if (comp.__esModule && comp.default) {
comp = comp.default
}
return isObject(comp)
? base.extend(comp)
: comp
Expand Down
3 changes: 3 additions & 0 deletions src/server/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,9 @@ function renderAsyncComponent (node, isRoot, context) {
const factory = node.asyncFactory

const resolve = comp => {
if (comp.__esModule && comp.default) {
comp = comp.default
}
const { data, children, tag } = node.asyncMeta
const nodeContext = node.asyncMeta.context
const resolvedNode: any = createComponent(
Expand Down
102 changes: 44 additions & 58 deletions test/ssr/ssr-string.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,7 @@ describe('SSR: renderToString', () => {
})
})

it('renders asynchronous component', done => {
it('renders async component', done => {
renderVmWithOptions({
template: `
<div>
Expand All @@ -482,11 +482,11 @@ describe('SSR: renderToString', () => {
`,
components: {
testAsync (resolve) {
resolve({
setTimeout(() => resolve({
render () {
return this.$createElement('span', { class: ['b'] }, 'testAsync')
}
})
}), 1)
}
}
}, result => {
Expand All @@ -495,55 +495,58 @@ describe('SSR: renderToString', () => {
})
})

it('renders asynchronous component (hoc)', done => {
it('renders async component (Promise, nested)', done => {
const Foo = () => Promise.resolve({
render: h => h('div', [h('span', 'foo'), h(Bar)])
})
const Bar = () => ({
component: Promise.resolve({
render: h => h('span', 'bar')
})
})
renderVmWithOptions({
template: '<test-async></test-async>',
components: {
testAsync (resolve) {
resolve({
render () {
return this.$createElement('span', { class: ['b'] }, 'testAsync')
}
})
}
render: h => h(Foo)
}, res => {
expect(res).toContain(`<div data-server-rendered="true"><span>foo</span><span>bar</span></div>`)
done()
})
})

it('renders async component (ES module)', done => {
const Foo = () => Promise.resolve({
__esModule: true,
default: {
render: h => h('div', [h('span', 'foo'), h(Bar)])
}
}, result => {
expect(result).toContain('<span data-server-rendered="true" class="b">testAsync</span>')
})
const Bar = () => ({
component: Promise.resolve({
__esModule: true,
default: {
render: h => h('span', 'bar')
}
})
})
renderVmWithOptions({
render: h => h(Foo)
}, res => {
expect(res).toContain(`<div data-server-rendered="true"><span>foo</span><span>bar</span></div>`)
done()
})
})

it('renders nested asynchronous component', done => {
it('renders async component (hoc)', done => {
renderVmWithOptions({
template: `
<div>
<test-async></test-async>
</div>
`,
template: '<test-async></test-async>',
components: {
testAsync (resolve) {
const options = {
template: `
<span class="b">
<test-sub-async></test-sub-async>
</span>
`
}

options.components = {
testSubAsync (resolve) {
resolve({
render () {
return this.$createElement('div', { class: ['c'] }, 'testSubAsync')
}
})
}
testAsync: () => Promise.resolve({
render () {
return this.$createElement('span', { class: ['b'] }, 'testAsync')
}
resolve(options)
}
})
}
}, result => {
expect(result).toContain('<div data-server-rendered="true"><span class="b"><div class="c">testSubAsync</div></span></div>')
expect(result).toContain('<span data-server-rendered="true" class="b">testAsync</span>')
done()
})
})
Expand Down Expand Up @@ -877,23 +880,6 @@ describe('SSR: renderToString', () => {
done()
})
})

it('render async components', done => {
const Foo = () => Promise.resolve({
render: h => h('div', [h('span', 'foo'), h(Bar)])
})
const Bar = () => ({
component: Promise.resolve({
render: h => h('span', 'bar')
})
})
renderVmWithOptions({
render: h => h(Foo)
}, res => {
expect(res).toContain(`<div data-server-rendered="true"><span>foo</span><span>bar</span></div>`)
done()
})
})
})

function renderVmWithOptions (options, cb) {
Expand Down
27 changes: 27 additions & 0 deletions test/unit/features/component/component-async.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,33 @@ describe('Component async', () => {
}
})

it('resolve ES module default', done => {
const vm = new Vue({
template: '<div><test></test></div>',
components: {
test: (resolve) => {
setTimeout(() => {
resolve({
__esModule: true,
default: {
template: '<div>hi</div>'
}
})
// wait for parent update
Vue.nextTick(next)
}, 0)
}
}
}).$mount()
expect(vm.$el.innerHTML).toBe('<!---->')
expect(vm.$children.length).toBe(0)
function next () {
expect(vm.$el.innerHTML).toBe('<div>hi</div>')
expect(vm.$children.length).toBe(1)
done()
}
})

it('as root', done => {
const vm = new Vue({
template: '<test></test>',
Expand Down

0 comments on commit 0cd6ef3

Please sign in to comment.