ソースを参照

Streaming render for weex

fix append mode for keep-alive reactivation

streaming render for weex

fix weex test case

inject __WEEX__ during tests

fix append:tree for iOS

ignore weex branch
Evan You 9 年 前
コミット
9dce7adfa2

+ 3 - 0
.eslintrc

@@ -3,6 +3,9 @@
   "parser": "babel-eslint",
   "extends": "vue",
   "plugins": ["flowtype"],
+  "globals": {
+    "__WEEX__": true
+  },
   "rules": {
     "no-useless-escape": 0,
     "flowtype/define-flow-type": 1,

+ 5 - 0
build/config.js

@@ -78,12 +78,14 @@ const builds = {
   },
   // Weex runtime framework (CommonJS).
   'weex-framework': {
+    weex: true,
     entry: path.resolve(__dirname, '../src/entries/weex-framework.js'),
     dest: path.resolve(__dirname, '../packages/weex-vue-framework/index.js'),
     format: 'cjs'
   },
   // Weex compiler (CommonJS). Used by Weex's Webpack loader.
   'weex-compiler': {
+    weex: true,
     entry: path.resolve(__dirname, '../src/entries/weex-compiler.js'),
     dest: path.resolve(__dirname, '../packages/weex-template-compiler/build.js'),
     format: 'cjs',
@@ -100,6 +102,9 @@ function genConfig (opts) {
     banner: opts.banner,
     moduleName: 'Vue',
     plugins: [
+      replace({
+        __WEEX__: !!opts.weex
+      }),
       flow(),
       buble(),
       alias(Object.assign({}, require('./alias'), opts.alias))

+ 1 - 0
build/karma.base.config.js

@@ -16,6 +16,7 @@ var webpackConfig = {
   },
   plugins: [
     new webpack.DefinePlugin({
+      __WEEX__: false,
       'process.env': {
         NODE_ENV: '"development"',
         TRANSITION_DURATION: process.env.SAUCE ? 200 : 50,

+ 1 - 1
flow/compiler.js

@@ -125,7 +125,7 @@ declare type ASTElement = {
   wrapData?: (code: string) => string;
 
   // weex specific
-  atom?: boolean;
+  appendAsTree?: boolean;
 }
 
 declare type ASTExpression = {

+ 4 - 0
flow/options.js

@@ -6,6 +6,8 @@ declare type InternalComponentOptions = {
   _parentListeners: ?Object;
   _renderChildren: ?VNodeChildren;
   _componentTag: ?string;
+  _parentElm: ?Node;
+  _refElm: ?Node;
   render?: Function;
   staticRenderFns?: Array<Function>
 }
@@ -61,6 +63,8 @@ declare type ComponentOptions = {
   _componentTag: ?string;
   _scopeId: ?string;
   _base: Class<Component>;
+  _parentElm: ?Node;
+  _refElm: ?Node;
 }
 
 declare type PropOptions = {

+ 2 - 0
src/core/instance/init.js

@@ -55,6 +55,8 @@ function initInternalComponent (vm: Component, options: InternalComponentOptions
   opts._parentListeners = options._parentListeners
   opts._renderChildren = options._renderChildren
   opts._componentTag = options._componentTag
+  opts._parentElm = options._parentElm
+  opts._refElm = options._refElm
   if (options.render) {
     opts.render = options.render
     opts.staticRenderFns = options.staticRenderFns

+ 10 - 4
src/core/instance/lifecycle.js

@@ -79,15 +79,21 @@ export function lifecycleMixin (Vue: Class<Component>) {
       callHook(vm, 'beforeUpdate')
     }
     const prevEl = vm.$el
+    const prevVnode = vm._vnode
     const prevActiveInstance = activeInstance
     activeInstance = vm
-    const prevVnode = vm._vnode
     vm._vnode = vnode
+    // Vue.prototype.__patch__ is injected in entry points
+    // based on the rendering backend used.
     if (!prevVnode) {
-      // Vue.prototype.__patch__ is injected in entry points
-      // based on the rendering backend used.
-      vm.$el = vm.__patch__(vm.$el, vnode, hydrating)
+      // initial render
+      vm.$el = vm.__patch__(
+        vm.$el, vnode, hydrating, false /* removeOnly */,
+        vm.$options._parentElm,
+        vm.$options._refElm
+      )
     } else {
+      // updates
       vm.$el = vm.__patch__(prevVnode, vnode)
     }
     activeInstance = prevActiveInstance

+ 19 - 4
src/core/vdom/create-component.js

@@ -129,7 +129,9 @@ function createFunctionalComponent (
 
 export function createComponentInstanceForVnode (
   vnode: any, // we know it's MountedComponentVNode but flow doesn't
-  parent: any // activeInstance in lifecycle state
+  parent: any, // activeInstance in lifecycle state
+  parentElm?: ?Node,
+  refElm?: ?Node
 ): Component {
   const vnodeComponentOptions = vnode.componentOptions
   const options: InternalComponentOptions = {
@@ -139,7 +141,9 @@ export function createComponentInstanceForVnode (
     _componentTag: vnodeComponentOptions.tag,
     _parentVnode: vnode,
     _parentListeners: vnodeComponentOptions.listeners,
-    _renderChildren: vnodeComponentOptions.children
+    _renderChildren: vnodeComponentOptions.children,
+    _parentElm: parentElm || null,
+    _refElm: refElm || null
   }
   // check inline-template render functions
   const inlineTemplate = vnode.data.inlineTemplate
@@ -150,14 +154,25 @@ export function createComponentInstanceForVnode (
   return new vnodeComponentOptions.Ctor(options)
 }
 
-function init (vnode: VNodeWithData, hydrating: boolean) {
+function init (
+  vnode: VNodeWithData,
+  hydrating: boolean,
+  parentElm: ?Node,
+  refElm: ?Node
+): ?boolean {
   if (!vnode.child || vnode.child._isDestroyed) {
-    const child = vnode.child = createComponentInstanceForVnode(vnode, activeInstance)
+    const child = vnode.child = createComponentInstanceForVnode(
+      vnode,
+      activeInstance,
+      parentElm,
+      refElm
+    )
     child.$mount(hydrating ? vnode.elm : undefined, hydrating)
   } else if (vnode.data.keepAlive) {
     // kept-alive components, treat as a patch
     const mountedNode: any = vnode // work around flow
     prepatch(mountedNode, mountedNode)
+    return true // let the patcher know this is a reactivated component
   }
 }
 

+ 63 - 24
src/core/vdom/patch.js

@@ -85,19 +85,26 @@ export function createPatchFunction (backend) {
   }
 
   let inPre = 0
-  function createElm (vnode, insertedVnodeQueue, nested) {
-    let i
+  function createElm (vnode, insertedVnodeQueue, parentElm, refElm, nested) {
+    let i, isReactivated
     const data = vnode.data
     vnode.isRootInsert = !nested
     if (isDef(data)) {
-      if (isDef(i = data.hook) && isDef(i = i.init)) i(vnode)
+      if (isDef(i = data.hook) && isDef(i = i.init)) {
+        isReactivated = i(vnode, false /* hydrating */, parentElm, refElm)
+      }
       // after calling the init hook, if the vnode is a child component
       // it should've created a child instance and mounted it. the child
       // component also has set the placeholder vnode's elm.
       // in that case we can just return the element and be done.
       if (isDef(i = vnode.child)) {
         initComponent(vnode, insertedVnodeQueue)
-        return vnode.elm
+        if (isReactivated) {
+          // unlike a newly created component,
+          // a reactivated keep-alive component doesn't insert itself
+          insert(parentElm, vnode.child.$el, refElm)
+        }
+        return
       }
     }
     const children = vnode.children
@@ -125,25 +132,56 @@ export function createPatchFunction (backend) {
         ? nodeOps.createElementNS(vnode.ns, tag)
         : nodeOps.createElement(tag, vnode)
       setScope(vnode)
-      createChildren(vnode, children, insertedVnodeQueue)
-      if (isDef(data)) {
-        invokeCreateHooks(vnode, insertedVnodeQueue)
+
+      /* istanbul ignore if */
+      if (__WEEX__) {
+        // in Weex, the default insertion order is parent-first.
+        // List items can be optimized to use children-first insertion
+        // with append="tree".
+        const appendAsTree = data && data.appendAsTree
+        if (!appendAsTree) {
+          if (isDef(data)) {
+            invokeCreateHooks(vnode, insertedVnodeQueue)
+          }
+          insert(parentElm, vnode.elm, refElm)
+        }
+        createChildren(vnode, children, insertedVnodeQueue)
+        if (appendAsTree) {
+          if (isDef(data)) {
+            invokeCreateHooks(vnode, insertedVnodeQueue)
+          }
+          insert(parentElm, vnode.elm, refElm)
+        }
+      } else {
+        createChildren(vnode, children, insertedVnodeQueue)
+        if (isDef(data)) {
+          invokeCreateHooks(vnode, insertedVnodeQueue)
+        }
+        insert(parentElm, vnode.elm, refElm)
       }
+
       if (process.env.NODE_ENV !== 'production' && data && data.pre) {
         inPre--
       }
     } else if (vnode.isComment) {
       vnode.elm = nodeOps.createComment(vnode.text)
+      insert(parentElm, vnode.elm, refElm)
     } else {
       vnode.elm = nodeOps.createTextNode(vnode.text)
+      insert(parentElm, vnode.elm, refElm)
+    }
+  }
+
+  function insert (parent, elm, ref) {
+    if (parent) {
+      nodeOps.insertBefore(parent, elm, ref)
     }
-    return vnode.elm
   }
 
   function createChildren (vnode, children, insertedVnodeQueue) {
     if (Array.isArray(children)) {
       for (let i = 0; i < children.length; ++i) {
-        nodeOps.appendChild(vnode.elm, createElm(children[i], insertedVnodeQueue, true))
+        createElm(children[i], insertedVnodeQueue, vnode.elm, null, true)
       }
     } else if (isPrimitive(vnode.text)) {
       nodeOps.appendChild(vnode.elm, nodeOps.createTextNode(vnode.text))
@@ -200,9 +238,9 @@ export function createPatchFunction (backend) {
     }
   }
 
-  function addVnodes (parentElm, before, vnodes, startIdx, endIdx, insertedVnodeQueue) {
+  function addVnodes (parentElm, refElm, vnodes, startIdx, endIdx, insertedVnodeQueue) {
     for (; startIdx <= endIdx; ++startIdx) {
-      nodeOps.insertBefore(parentElm, createElm(vnodes[startIdx], insertedVnodeQueue), before)
+      createElm(vnodes[startIdx], insertedVnodeQueue, parentElm, refElm)
     }
   }
 
@@ -271,7 +309,7 @@ export function createPatchFunction (backend) {
     let newEndIdx = newCh.length - 1
     let newStartVnode = newCh[0]
     let newEndVnode = newCh[newEndIdx]
-    let oldKeyToIdx, idxInOld, elmToMove, before
+    let oldKeyToIdx, idxInOld, elmToMove, refElm
 
     // removeOnly is a special flag used only by <transition-group>
     // to ensure removed elements stay in correct relative positions
@@ -305,7 +343,7 @@ export function createPatchFunction (backend) {
         if (isUndef(oldKeyToIdx)) oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx)
         idxInOld = isDef(newStartVnode.key) ? oldKeyToIdx[newStartVnode.key] : null
         if (isUndef(idxInOld)) { // New element
-          nodeOps.insertBefore(parentElm, createElm(newStartVnode, insertedVnodeQueue), oldStartVnode.elm)
+          createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm)
           newStartVnode = newCh[++newStartIdx]
         } else {
           elmToMove = oldCh[idxInOld]
@@ -318,7 +356,7 @@ export function createPatchFunction (backend) {
           }
           if (elmToMove.tag !== newStartVnode.tag) {
             // same key but different element. treat as new element
-            nodeOps.insertBefore(parentElm, createElm(newStartVnode, insertedVnodeQueue), oldStartVnode.elm)
+            createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm)
             newStartVnode = newCh[++newStartIdx]
           } else {
             patchVnode(elmToMove, newStartVnode, insertedVnodeQueue)
@@ -330,8 +368,8 @@ export function createPatchFunction (backend) {
       }
     }
     if (oldStartIdx > oldEndIdx) {
-      before = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm
-      addVnodes(parentElm, before, newCh, newStartIdx, newEndIdx, insertedVnodeQueue)
+      refElm = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm
+      addVnodes(parentElm, refElm, newCh, newStartIdx, newEndIdx, insertedVnodeQueue)
     } else if (newStartIdx > newEndIdx) {
       removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx)
     }
@@ -462,7 +500,7 @@ export function createPatchFunction (backend) {
     }
   }
 
-  return function patch (oldVnode, vnode, hydrating, removeOnly) {
+  return function patch (oldVnode, vnode, hydrating, removeOnly, parentElm, refElm) {
     if (!vnode) {
       if (oldVnode) invokeDestroyHook(oldVnode)
       return
@@ -473,12 +511,13 @@ export function createPatchFunction (backend) {
     const insertedVnodeQueue = []
 
     if (!oldVnode) {
-      // empty mount, create new root element
+      // empty mount (likely as component), create new root element
       isInitialPatch = true
-      createElm(vnode, insertedVnodeQueue)
+      createElm(vnode, insertedVnodeQueue, parentElm, refElm)
     } else {
       const isRealElement = isDef(oldVnode.nodeType)
       if (!isRealElement && sameVnode(oldVnode, vnode)) {
+        // patch existing root node
         patchVnode(oldVnode, vnode, insertedVnodeQueue, removeOnly)
       } else {
         if (isRealElement) {
@@ -507,14 +546,15 @@ export function createPatchFunction (backend) {
           // create an empty node and replace it
           oldVnode = emptyNodeAt(oldVnode)
         }
+
+        // replacing existing element
         elm = oldVnode.elm
         parent = nodeOps.parentNode(elm)
+        createElm(vnode, insertedVnodeQueue, parent, nodeOps.nextSibling(elm))
 
-        createElm(vnode, insertedVnodeQueue)
-
-        // component root element replaced.
-        // update parent placeholder node element, recursively
         if (vnode.parent) {
+          // component root element replaced.
+          // update parent placeholder node element, recursively
           let ancestor = vnode.parent
           while (ancestor) {
             ancestor.elm = vnode.elm
@@ -528,7 +568,6 @@ export function createPatchFunction (backend) {
         }
 
         if (parent !== null) {
-          nodeOps.insertBefore(parent, vnode.elm, nodeOps.nextSibling(elm))
           removeVnodes(parent, [oldVnode], 0, 0)
         } else if (isDef(oldVnode.tag)) {
           invokeDestroyHook(oldVnode)

+ 6 - 11
src/platforms/weex/compiler/modules/append.js

@@ -1,22 +1,17 @@
 /* @flow */
 
-import {
-  getAndRemoveAttr
-} from 'compiler/helpers'
-
-function parse (el: ASTElement, options: CompilerOptions) {
-  const staticStyle = getAndRemoveAttr(el, 'append')
-  if (staticStyle === 'tree') {
-    el.atom = true
+function transformNode (el: ASTElement, options: CompilerOptions) {
+  if (el.attrsMap.append === 'tree') {
+    el.appendAsTree = true
   }
 }
 
 function genData (el: ASTElement): string {
-  return el.atom ? `atom:true,` : ''
+  return el.appendAsTree ? `appendAsTree:true,` : ''
 }
 
 export default {
-  staticKeys: ['atom'],
-  parse,
+  staticKeys: ['appendAsTree'],
+  transformNode,
   genData
 }

+ 3 - 0
src/platforms/weex/runtime/node-ops.js

@@ -19,6 +19,9 @@ export function createComment (text) {
 }
 
 export function insertBefore (node, target, before) {
+  if (!before) {
+    return appendChild(node, target)
+  }
   if (target.nodeType === 3) {
     if (node.type === 'text') {
       node.setAttr('value', target.text)

+ 5 - 1
src/platforms/weex/runtime/patch.js

@@ -9,4 +9,8 @@ import platformModules from 'weex/runtime/modules/index'
 // built-in modules have been applied.
 const modules = platformModules.concat(baseModules)
 
-export const patch: Function = createPatchFunction({ nodeOps, modules })
+export const patch: Function = createPatchFunction({
+  nodeOps,
+  modules,
+  LONG_LIST_THRESHOLD: 10
+})