Permalink
Browse files

support async hydration

  • Loading branch information...
yyx990803 committed May 19, 2017
1 parent f3757eb commit 7404091896fda2c87ecac64efc24324ff1885e2c
@@ -15,6 +15,7 @@ import {
import {
resolveAsyncComponent,
createAsyncPlaceholder,
extractPropsFromVNodeData
} from './helpers/index'
@@ -122,22 +123,24 @@ export function createComponent (
return
}
data = data || {}
// async component
let asyncFactory
if (isUndef(Ctor.cid)) {
Ctor = resolveAsyncComponent(Ctor, baseCtor, context)
asyncFactory = Ctor
Ctor = resolveAsyncComponent(asyncFactory, baseCtor, context)
if (Ctor === undefined) {
// return nothing if this is indeed an async component
// wait for the callback to trigger parent update.
return
return createAsyncPlaceholder(asyncFactory, data.key)
}
}
// resolve constructor options in case global mixins are applied after
// component constructor creation
resolveConstructorOptions(Ctor)
data = data || {}
// transform component v-model data into props & events
if (isDef(data.model)) {
transformModel(Ctor.options, data)
@@ -171,7 +174,8 @@ export function createComponent (
const vnode = new VNode(
`vue-component-${Ctor.cid}${name ? `-${name}` : ''}`,
data, undefined, undefined, undefined, context,
{ Ctor, propsData, listeners, tag, children }
{ Ctor, propsData, listeners, tag, children },
asyncFactory
)
return vnode
}
@@ -9,12 +9,24 @@ import {
isObject
} from 'core/util/index'
import { createEmptyVNode } from 'core/vdom/vnode'
function ensureCtor (comp, base) {
return isObject(comp)
? base.extend(comp)
: comp
}
export function createAsyncPlaceholder (
factory: Function,
key: string | number | void
): VNode {
const node = createEmptyVNode()
node.asyncFactory = factory
node.key = key
return node
}
export function resolveAsyncComponent (
factory: Function,
baseCtor: Class<Component>,
View
@@ -33,11 +33,17 @@ const hooks = ['create', 'activate', 'update', 'remove', 'destroy']
function sameVnode (a, b) {
return (
a.key === b.key &&
a.tag === b.tag &&
a.isComment === b.isComment &&
isDef(a.data) === isDef(b.data) &&
sameInputType(a, b)
a.key === b.key && (
(
a.isAsyncPlaceholder === true &&
a.asyncFactory === b.asyncFactory
) || (
a.tag === b.tag &&
a.isComment === b.isComment &&
isDef(a.data) === isDef(b.data) &&
sameInputType(a, b)
)
)
)
}
@@ -434,6 +440,9 @@ export function createPatchFunction (backend) {
if (oldVnode === vnode) {
return
}
if (oldVnode.isAsyncPlaceholder) {
return hydrate(oldVnode.elm, vnode, insertedVnodeQueue)
}
// reuse element for static trees.
// note we only do this if the vnode is cloned -
// if the new node is not cloned it means the render functions have been
@@ -497,6 +506,11 @@ export function createPatchFunction (backend) {
// Note: this is a browser-only function so we can assume elms are DOM nodes.
function hydrate (elm, vnode, insertedVnodeQueue) {
if (isTrue(vnode.isComment) && isDef(vnode.asyncFactory)) {
vnode.elm = elm
vnode.isAsyncPlaceholder = true
return true
}
if (process.env.NODE_ENV !== 'production') {
if (!assertNodeMatch(elm, vnode)) {
return false
View
@@ -19,6 +19,8 @@ export default class VNode {
isComment: boolean; // empty comment placeholder?
isCloned: boolean; // is a cloned node?
isOnce: boolean; // is a v-once node?
asyncFactory: ?Function; // async component factory function
isAsyncPlaceholder: boolean;
constructor (
tag?: string,
@@ -27,7 +29,8 @@ export default class VNode {
text?: string,
elm?: Node,
context?: Component,
componentOptions?: VNodeComponentOptions
componentOptions?: VNodeComponentOptions,
asyncFactory?: Function
) {
this.tag = tag
this.data = data
@@ -47,6 +50,8 @@ export default class VNode {
this.isComment = false
this.isCloned = false
this.isOnce = false
this.asyncFactory = asyncFactory
this.isAsyncPlaceholder = false
}
// DEPRECATED: alias for componentInstance for backwards compat.
@@ -61,7 +61,8 @@ describe('create-component', () => {
}
function go () {
vnode = createComponent(async, data, vm, vm)
expect(vnode).toBeUndefined() // not to be loaded yet.
expect(vnode.isComment).toBe(true) // not to be loaded yet.
expect(vnode.asyncFactory).toBe(async)
}
function loaded () {
vnode = createComponent(async, data, vm, vm)
@@ -93,11 +94,11 @@ describe('create-component', () => {
}
function go () {
vnode = createComponent(async, data, vm, vm)
expect(vnode).toBeUndefined() // not to be loaded yet.
expect(vnode.isComment).toBe(true) // not to be loaded yet.
}
function failed () {
vnode = createComponent(async, data, vm, vm)
expect(vnode).toBeUndefined() // failed
expect(vnode.isComment).toBe(true) // failed, still a comment node
expect(`Failed to resolve async component: ${async}\nReason: ${reason}`).toHaveBeenWarned()
done()
}

0 comments on commit 7404091

Please sign in to comment.