Skip to content

Commit 0cd6ef3

Browse files
committed
feat: resolve ES module default when resolving async components
1 parent b5f08f3 commit 0cd6ef3

File tree

4 files changed

+77
-58
lines changed

4 files changed

+77
-58
lines changed

src/core/vdom/helpers/resolve-async-component.js

+3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ import {
1212
import { createEmptyVNode } from 'core/vdom/vnode'
1313

1414
function ensureCtor (comp, base) {
15+
if (comp.__esModule && comp.default) {
16+
comp = comp.default
17+
}
1518
return isObject(comp)
1619
? base.extend(comp)
1720
: comp

src/server/render.js

+3
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,9 @@ function renderAsyncComponent (node, isRoot, context) {
172172
const factory = node.asyncFactory
173173

174174
const resolve = comp => {
175+
if (comp.__esModule && comp.default) {
176+
comp = comp.default
177+
}
175178
const { data, children, tag } = node.asyncMeta
176179
const nodeContext = node.asyncMeta.context
177180
const resolvedNode: any = createComponent(

test/ssr/ssr-string.spec.js

+44-58
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ describe('SSR: renderToString', () => {
473473
})
474474
})
475475

476-
it('renders asynchronous component', done => {
476+
it('renders async component', done => {
477477
renderVmWithOptions({
478478
template: `
479479
<div>
@@ -482,11 +482,11 @@ describe('SSR: renderToString', () => {
482482
`,
483483
components: {
484484
testAsync (resolve) {
485-
resolve({
485+
setTimeout(() => resolve({
486486
render () {
487487
return this.$createElement('span', { class: ['b'] }, 'testAsync')
488488
}
489-
})
489+
}), 1)
490490
}
491491
}
492492
}, result => {
@@ -495,55 +495,58 @@ describe('SSR: renderToString', () => {
495495
})
496496
})
497497

498-
it('renders asynchronous component (hoc)', done => {
498+
it('renders async component (Promise, nested)', done => {
499+
const Foo = () => Promise.resolve({
500+
render: h => h('div', [h('span', 'foo'), h(Bar)])
501+
})
502+
const Bar = () => ({
503+
component: Promise.resolve({
504+
render: h => h('span', 'bar')
505+
})
506+
})
499507
renderVmWithOptions({
500-
template: '<test-async></test-async>',
501-
components: {
502-
testAsync (resolve) {
503-
resolve({
504-
render () {
505-
return this.$createElement('span', { class: ['b'] }, 'testAsync')
506-
}
507-
})
508-
}
508+
render: h => h(Foo)
509+
}, res => {
510+
expect(res).toContain(`<div data-server-rendered="true"><span>foo</span><span>bar</span></div>`)
511+
done()
512+
})
513+
})
514+
515+
it('renders async component (ES module)', done => {
516+
const Foo = () => Promise.resolve({
517+
__esModule: true,
518+
default: {
519+
render: h => h('div', [h('span', 'foo'), h(Bar)])
509520
}
510-
}, result => {
511-
expect(result).toContain('<span data-server-rendered="true" class="b">testAsync</span>')
521+
})
522+
const Bar = () => ({
523+
component: Promise.resolve({
524+
__esModule: true,
525+
default: {
526+
render: h => h('span', 'bar')
527+
}
528+
})
529+
})
530+
renderVmWithOptions({
531+
render: h => h(Foo)
532+
}, res => {
533+
expect(res).toContain(`<div data-server-rendered="true"><span>foo</span><span>bar</span></div>`)
512534
done()
513535
})
514536
})
515537

516-
it('renders nested asynchronous component', done => {
538+
it('renders async component (hoc)', done => {
517539
renderVmWithOptions({
518-
template: `
519-
<div>
520-
<test-async></test-async>
521-
</div>
522-
`,
540+
template: '<test-async></test-async>',
523541
components: {
524-
testAsync (resolve) {
525-
const options = {
526-
template: `
527-
<span class="b">
528-
<test-sub-async></test-sub-async>
529-
</span>
530-
`
531-
}
532-
533-
options.components = {
534-
testSubAsync (resolve) {
535-
resolve({
536-
render () {
537-
return this.$createElement('div', { class: ['c'] }, 'testSubAsync')
538-
}
539-
})
540-
}
542+
testAsync: () => Promise.resolve({
543+
render () {
544+
return this.$createElement('span', { class: ['b'] }, 'testAsync')
541545
}
542-
resolve(options)
543-
}
546+
})
544547
}
545548
}, result => {
546-
expect(result).toContain('<div data-server-rendered="true"><span class="b"><div class="c">testSubAsync</div></span></div>')
549+
expect(result).toContain('<span data-server-rendered="true" class="b">testAsync</span>')
547550
done()
548551
})
549552
})
@@ -877,23 +880,6 @@ describe('SSR: renderToString', () => {
877880
done()
878881
})
879882
})
880-
881-
it('render async components', done => {
882-
const Foo = () => Promise.resolve({
883-
render: h => h('div', [h('span', 'foo'), h(Bar)])
884-
})
885-
const Bar = () => ({
886-
component: Promise.resolve({
887-
render: h => h('span', 'bar')
888-
})
889-
})
890-
renderVmWithOptions({
891-
render: h => h(Foo)
892-
}, res => {
893-
expect(res).toContain(`<div data-server-rendered="true"><span>foo</span><span>bar</span></div>`)
894-
done()
895-
})
896-
})
897883
})
898884

899885
function renderVmWithOptions (options, cb) {

test/unit/features/component/component-async.spec.js

+27
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,33 @@ describe('Component async', () => {
2626
}
2727
})
2828

29+
it('resolve ES module default', done => {
30+
const vm = new Vue({
31+
template: '<div><test></test></div>',
32+
components: {
33+
test: (resolve) => {
34+
setTimeout(() => {
35+
resolve({
36+
__esModule: true,
37+
default: {
38+
template: '<div>hi</div>'
39+
}
40+
})
41+
// wait for parent update
42+
Vue.nextTick(next)
43+
}, 0)
44+
}
45+
}
46+
}).$mount()
47+
expect(vm.$el.innerHTML).toBe('<!---->')
48+
expect(vm.$children.length).toBe(0)
49+
function next () {
50+
expect(vm.$el.innerHTML).toBe('<div>hi</div>')
51+
expect(vm.$children.length).toBe(1)
52+
done()
53+
}
54+
})
55+
2956
it('as root', done => {
3057
const vm = new Vue({
3158
template: '<test></test>',

0 commit comments

Comments
 (0)