Skip to content

Commit 39a231d

Browse files
committed
Streaming render for weex
fix append mode for keep-alive reactivation streaming render for weex
1 parent 68e560a commit 39a231d

File tree

8 files changed

+116
-33
lines changed

8 files changed

+116
-33
lines changed

.eslintrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
"parser": "babel-eslint",
44
"extends": "vue",
55
"plugins": ["flowtype"],
6+
"globals": {
7+
"__WEEX__": true
8+
},
69
"rules": {
710
"no-useless-escape": 0,
811
"flowtype/define-flow-type": 1,

build/config.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,14 @@ const builds = {
7878
},
7979
// Weex runtime framework (CommonJS).
8080
'weex-framework': {
81+
weex: true,
8182
entry: path.resolve(__dirname, '../src/entries/weex-framework.js'),
8283
dest: path.resolve(__dirname, '../packages/weex-vue-framework/index.js'),
8384
format: 'cjs'
8485
},
8586
// Weex compiler (CommonJS). Used by Weex's Webpack loader.
8687
'weex-compiler': {
88+
weex: true,
8789
entry: path.resolve(__dirname, '../src/entries/weex-compiler.js'),
8890
dest: path.resolve(__dirname, '../packages/weex-template-compiler/build.js'),
8991
format: 'cjs',
@@ -100,6 +102,9 @@ function genConfig (opts) {
100102
banner: opts.banner,
101103
moduleName: 'Vue',
102104
plugins: [
105+
replace({
106+
__WEEX__: !!opts.weex
107+
}),
103108
flow(),
104109
buble(),
105110
alias(Object.assign({}, require('./alias'), opts.alias))

flow/options.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ declare type InternalComponentOptions = {
66
_parentListeners: ?Object;
77
_renderChildren: ?VNodeChildren;
88
_componentTag: ?string;
9+
_parentElm: ?Node;
10+
_refElm: ?Node;
911
render?: Function;
1012
staticRenderFns?: Array<Function>
1113
}
@@ -61,6 +63,8 @@ declare type ComponentOptions = {
6163
_componentTag: ?string;
6264
_scopeId: ?string;
6365
_base: Class<Component>;
66+
_parentElm: ?Node;
67+
_refElm: ?Node;
6468
}
6569

6670
declare type PropOptions = {

src/core/instance/init.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ function initInternalComponent (vm: Component, options: InternalComponentOptions
5555
opts._parentListeners = options._parentListeners
5656
opts._renderChildren = options._renderChildren
5757
opts._componentTag = options._componentTag
58+
opts._parentElm = options._parentElm
59+
opts._refElm = options._refElm
5860
if (options.render) {
5961
opts.render = options.render
6062
opts.staticRenderFns = options.staticRenderFns

src/core/instance/lifecycle.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,15 +79,21 @@ export function lifecycleMixin (Vue: Class<Component>) {
7979
callHook(vm, 'beforeUpdate')
8080
}
8181
const prevEl = vm.$el
82+
const prevVnode = vm._vnode
8283
const prevActiveInstance = activeInstance
8384
activeInstance = vm
84-
const prevVnode = vm._vnode
8585
vm._vnode = vnode
86+
// Vue.prototype.__patch__ is injected in entry points
87+
// based on the rendering backend used.
8688
if (!prevVnode) {
87-
// Vue.prototype.__patch__ is injected in entry points
88-
// based on the rendering backend used.
89-
vm.$el = vm.__patch__(vm.$el, vnode, hydrating)
89+
// initial render
90+
vm.$el = vm.__patch__(
91+
vm.$el, vnode, hydrating, false /* removeOnly */,
92+
vm.$options._parentElm,
93+
vm.$options._refElm
94+
)
9095
} else {
96+
// updates
9197
vm.$el = vm.__patch__(prevVnode, vnode)
9298
}
9399
activeInstance = prevActiveInstance

src/core/vdom/create-component.js

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,9 @@ function createFunctionalComponent (
129129

130130
export function createComponentInstanceForVnode (
131131
vnode: any, // we know it's MountedComponentVNode but flow doesn't
132-
parent: any // activeInstance in lifecycle state
132+
parent: any, // activeInstance in lifecycle state
133+
parentElm?: ?Node,
134+
refElm?: ?Node
133135
): Component {
134136
const vnodeComponentOptions = vnode.componentOptions
135137
const options: InternalComponentOptions = {
@@ -139,7 +141,9 @@ export function createComponentInstanceForVnode (
139141
_componentTag: vnodeComponentOptions.tag,
140142
_parentVnode: vnode,
141143
_parentListeners: vnodeComponentOptions.listeners,
142-
_renderChildren: vnodeComponentOptions.children
144+
_renderChildren: vnodeComponentOptions.children,
145+
_parentElm: parentElm || null,
146+
_refElm: refElm || null
143147
}
144148
// check inline-template render functions
145149
const inlineTemplate = vnode.data.inlineTemplate
@@ -150,14 +154,25 @@ export function createComponentInstanceForVnode (
150154
return new vnodeComponentOptions.Ctor(options)
151155
}
152156

153-
function init (vnode: VNodeWithData, hydrating: boolean) {
157+
function init (
158+
vnode: VNodeWithData,
159+
hydrating: boolean,
160+
parentElm: ?Node,
161+
refElm: ?Node
162+
): ?boolean {
154163
if (!vnode.child || vnode.child._isDestroyed) {
155-
const child = vnode.child = createComponentInstanceForVnode(vnode, activeInstance)
164+
const child = vnode.child = createComponentInstanceForVnode(
165+
vnode,
166+
activeInstance,
167+
parentElm,
168+
refElm
169+
)
156170
child.$mount(hydrating ? vnode.elm : undefined, hydrating)
157171
} else if (vnode.data.keepAlive) {
158172
// kept-alive components, treat as a patch
159173
const mountedNode: any = vnode // work around flow
160174
prepatch(mountedNode, mountedNode)
175+
return true // let the patcher know this is a reactivated component
161176
}
162177
}
163178

src/core/vdom/patch.js

Lines changed: 68 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -85,19 +85,26 @@ export function createPatchFunction (backend) {
8585
}
8686

8787
let inPre = 0
88-
function createElm (vnode, insertedVnodeQueue, nested) {
89-
let i
88+
function createElm (vnode, insertedVnodeQueue, parentElm, refElm, nested) {
89+
let i, isReactivated
9090
const data = vnode.data
9191
vnode.isRootInsert = !nested
9292
if (isDef(data)) {
93-
if (isDef(i = data.hook) && isDef(i = i.init)) i(vnode)
93+
if (isDef(i = data.hook) && isDef(i = i.init)) {
94+
isReactivated = i(vnode, false /* hydrating */, parentElm, refElm)
95+
}
9496
// after calling the init hook, if the vnode is a child component
9597
// it should've created a child instance and mounted it. the child
9698
// component also has set the placeholder vnode's elm.
9799
// in that case we can just return the element and be done.
98100
if (isDef(i = vnode.child)) {
99101
initComponent(vnode, insertedVnodeQueue)
100-
return vnode.elm
102+
if (isReactivated) {
103+
// unlike a newly created component,
104+
// a reactivated keep-alive component doesn't insert itself
105+
insert(parentElm, vnode.child.$el, refElm)
106+
}
107+
return
101108
}
102109
}
103110
const children = vnode.children
@@ -125,25 +132,61 @@ export function createPatchFunction (backend) {
125132
? nodeOps.createElementNS(vnode.ns, tag)
126133
: nodeOps.createElement(tag, vnode)
127134
setScope(vnode)
128-
createChildren(vnode, children, insertedVnodeQueue)
129-
if (isDef(data)) {
130-
invokeCreateHooks(vnode, insertedVnodeQueue)
135+
136+
if (__WEEX__) {
137+
// Detect long lists:
138+
// If the list is longer than a certain threshold, it may take to long
139+
// to compute the whole tree before being able to send messages to the
140+
// native client. When we detect such a case, we will append the parent
141+
// element FIRST, so that each child can be drawn as soon as possible
142+
// by the native client, resulting in faster initial render and better
143+
// perceived UX.
144+
const isLongList =
145+
Array.isArray(children) &&
146+
children.length >= backend.LONG_LIST_THRESHOLD
147+
if (isLongList) {
148+
if (isDef(data)) {
149+
invokeCreateHooks(vnode, insertedVnodeQueue)
150+
}
151+
insert(parentElm, vnode.elm, refElm)
152+
}
153+
createChildren(vnode, children, insertedVnodeQueue)
154+
if (!isLongList) {
155+
if (isDef(data)) {
156+
invokeCreateHooks(vnode, insertedVnodeQueue)
157+
}
158+
insert(parentElm, vnode.elm, refElm)
159+
}
160+
} else {
161+
createChildren(vnode, children, insertedVnodeQueue)
162+
if (isDef(data)) {
163+
invokeCreateHooks(vnode, insertedVnodeQueue)
164+
}
165+
insert(parentElm, vnode.elm, refElm)
131166
}
167+
132168
if (process.env.NODE_ENV !== 'production' && data && data.pre) {
133169
inPre--
134170
}
135171
} else if (vnode.isComment) {
136172
vnode.elm = nodeOps.createComment(vnode.text)
173+
insert(parentElm, vnode.elm, refElm)
137174
} else {
138175
vnode.elm = nodeOps.createTextNode(vnode.text)
176+
insert(parentElm, vnode.elm, refElm)
177+
}
178+
}
179+
180+
function insert (parent, elm, ref) {
181+
if (parent) {
182+
nodeOps.insertBefore(parent, elm, ref)
139183
}
140-
return vnode.elm
141184
}
142185

143186
function createChildren (vnode, children, insertedVnodeQueue) {
144187
if (Array.isArray(children)) {
145188
for (let i = 0; i < children.length; ++i) {
146-
nodeOps.appendChild(vnode.elm, createElm(children[i], insertedVnodeQueue, true))
189+
createElm(children[i], insertedVnodeQueue, vnode.elm, null, true)
147190
}
148191
} else if (isPrimitive(vnode.text)) {
149192
nodeOps.appendChild(vnode.elm, nodeOps.createTextNode(vnode.text))
@@ -200,9 +243,9 @@ export function createPatchFunction (backend) {
200243
}
201244
}
202245

203-
function addVnodes (parentElm, before, vnodes, startIdx, endIdx, insertedVnodeQueue) {
246+
function addVnodes (parentElm, refElm, vnodes, startIdx, endIdx, insertedVnodeQueue) {
204247
for (; startIdx <= endIdx; ++startIdx) {
205-
nodeOps.insertBefore(parentElm, createElm(vnodes[startIdx], insertedVnodeQueue), before)
248+
createElm(vnodes[startIdx], insertedVnodeQueue, parentElm, refElm)
206249
}
207250
}
208251

@@ -271,7 +314,7 @@ export function createPatchFunction (backend) {
271314
let newEndIdx = newCh.length - 1
272315
let newStartVnode = newCh[0]
273316
let newEndVnode = newCh[newEndIdx]
274-
let oldKeyToIdx, idxInOld, elmToMove, before
317+
let oldKeyToIdx, idxInOld, elmToMove, refElm
275318

276319
// removeOnly is a special flag used only by <transition-group>
277320
// to ensure removed elements stay in correct relative positions
@@ -305,7 +348,7 @@ export function createPatchFunction (backend) {
305348
if (isUndef(oldKeyToIdx)) oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx)
306349
idxInOld = isDef(newStartVnode.key) ? oldKeyToIdx[newStartVnode.key] : null
307350
if (isUndef(idxInOld)) { // New element
308-
nodeOps.insertBefore(parentElm, createElm(newStartVnode, insertedVnodeQueue), oldStartVnode.elm)
351+
createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm)
309352
newStartVnode = newCh[++newStartIdx]
310353
} else {
311354
elmToMove = oldCh[idxInOld]
@@ -318,7 +361,7 @@ export function createPatchFunction (backend) {
318361
}
319362
if (elmToMove.tag !== newStartVnode.tag) {
320363
// same key but different element. treat as new element
321-
nodeOps.insertBefore(parentElm, createElm(newStartVnode, insertedVnodeQueue), oldStartVnode.elm)
364+
createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm)
322365
newStartVnode = newCh[++newStartIdx]
323366
} else {
324367
patchVnode(elmToMove, newStartVnode, insertedVnodeQueue)
@@ -330,8 +373,8 @@ export function createPatchFunction (backend) {
330373
}
331374
}
332375
if (oldStartIdx > oldEndIdx) {
333-
before = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm
334-
addVnodes(parentElm, before, newCh, newStartIdx, newEndIdx, insertedVnodeQueue)
376+
refElm = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm
377+
addVnodes(parentElm, refElm, newCh, newStartIdx, newEndIdx, insertedVnodeQueue)
335378
} else if (newStartIdx > newEndIdx) {
336379
removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx)
337380
}
@@ -462,7 +505,7 @@ export function createPatchFunction (backend) {
462505
}
463506
}
464507

465-
return function patch (oldVnode, vnode, hydrating, removeOnly) {
508+
return function patch (oldVnode, vnode, hydrating, removeOnly, parentElm, refElm) {
466509
if (!vnode) {
467510
if (oldVnode) invokeDestroyHook(oldVnode)
468511
return
@@ -473,12 +516,13 @@ export function createPatchFunction (backend) {
473516
const insertedVnodeQueue = []
474517

475518
if (!oldVnode) {
476-
// empty mount, create new root element
519+
// empty mount (likely as component), create new root element
477520
isInitialPatch = true
478-
createElm(vnode, insertedVnodeQueue)
521+
createElm(vnode, insertedVnodeQueue, parentElm, refElm)
479522
} else {
480523
const isRealElement = isDef(oldVnode.nodeType)
481524
if (!isRealElement && sameVnode(oldVnode, vnode)) {
525+
// patch existing root node
482526
patchVnode(oldVnode, vnode, insertedVnodeQueue, removeOnly)
483527
} else {
484528
if (isRealElement) {
@@ -507,14 +551,15 @@ export function createPatchFunction (backend) {
507551
// create an empty node and replace it
508552
oldVnode = emptyNodeAt(oldVnode)
509553
}
554+
555+
// replacing existing element
510556
elm = oldVnode.elm
511557
parent = nodeOps.parentNode(elm)
558+
createElm(vnode, insertedVnodeQueue, parent, nodeOps.nextSibling(elm))
512559

513-
createElm(vnode, insertedVnodeQueue)
514-
515-
// component root element replaced.
516-
// update parent placeholder node element, recursively
517560
if (vnode.parent) {
561+
// component root element replaced.
562+
// update parent placeholder node element, recursively
518563
let ancestor = vnode.parent
519564
while (ancestor) {
520565
ancestor.elm = vnode.elm
@@ -528,7 +573,6 @@ export function createPatchFunction (backend) {
528573
}
529574

530575
if (parent !== null) {
531-
nodeOps.insertBefore(parent, vnode.elm, nodeOps.nextSibling(elm))
532576
removeVnodes(parent, [oldVnode], 0, 0)
533577
} else if (isDef(oldVnode.tag)) {
534578
invokeDestroyHook(oldVnode)

src/platforms/weex/runtime/patch.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,8 @@ import platformModules from 'weex/runtime/modules/index'
99
// built-in modules have been applied.
1010
const modules = platformModules.concat(baseModules)
1111

12-
export const patch: Function = createPatchFunction({ nodeOps, modules })
12+
export const patch: Function = createPatchFunction({
13+
nodeOps,
14+
modules,
15+
LONG_LIST_THRESHOLD: 10
16+
})

0 commit comments

Comments
 (0)