Browse Source

add optimizer

dev
Evan You 9 years ago
parent
commit
a5ea9020d1
  1. 2
      src/compiler/index.js
  2. 64
      src/compiler/optimizer/index.js
  3. 24
      src/compiler/parser/index.js

2
src/compiler/index.js

@ -1,4 +1,5 @@
import { parse } from './parser/index' import { parse } from './parser/index'
import { optimize } from './optimizer/index'
import { generate } from './codegen/index' import { generate } from './codegen/index'
import { directives } from './codegen/directives/index' import { directives } from './codegen/directives/index'
@ -14,6 +15,7 @@ export function compile (html, options) {
return hit return hit
} else { } else {
const ast = parse(html, options) const ast = parse(html, options)
optimize(ast)
return (cache[html] = generate(ast)) return (cache[html] = generate(ast))
} }
} }

64
src/compiler/optimizer/index.js

@ -0,0 +1,64 @@
import { makeMap } from '../../shared/util'
/**
* Goal of the optimizier: walk the generated template AST tree
* and detect sub-trees that are purely static, i.e. parts of
* the DOM that never needs to change.
*
* Once we detect these sub-trees, we can:
*
* 1. Hoist them into constants, so that we no longer need to
* create fresh nodes for them on each re-render;
* 2. Completely skip them in the patching process.
*/
export function optimize (root) {
// first pass: mark all dynamic nodes
mark(root)
debugger
// second pass: collect static roots
const staticRoots = []
sweep(root, staticRoots)
return staticRoots
}
function mark (node) {
node.dynamic = !isStatic(node)
if (node.children) {
for (let i = 0, l = node.children.length; i < l; i++) {
let child = node.children[i]
mark(child)
if (child.dynamic) {
node.dynamic = true
}
}
}
}
function sweep (node, staticRoots) {
if (node.tag && !node.dynamic) {
node.staticRoot = true
return
}
if (node.children) {
for (let i = 0, l = node.children.length; i < l; i++) {
sweep(node.children[i], staticRoots)
}
}
}
const isStaticKey = makeMap(
'tag,attrsList,attrsMap,plain,parent,children,' +
'staticAttrs,staticClass'
)
function isStatic (node) {
return node.pre || node.text || (
!node.render &&
!node.slotName &&
!node.component &&
!node.expression && (
node.plain || Object.keys(node).every(isStaticKey)
)
)
}

24
src/compiler/parser/index.js

@ -271,7 +271,10 @@ function processSlot (el) {
if (el.tag === 'slot') { if (el.tag === 'slot') {
el.slotName = getBindingAttr(el, 'name') el.slotName = getBindingAttr(el, 'name')
} else { } else {
el.slotTarget = getBindingAttr(el, 'slot') const slotTarget = getBindingAttr(el, 'slot')
if (slotTarget) {
el.slotTarget = slotTarget
}
} }
} }
@ -284,17 +287,26 @@ function processComponent (el) {
function processClassBinding (el) { function processClassBinding (el) {
const staticClass = getAndRemoveAttr(el, 'class') const staticClass = getAndRemoveAttr(el, 'class')
el.staticClass = parseText(staticClass) || JSON.stringify(staticClass) el.staticClass = parseText(staticClass) || JSON.stringify(staticClass)
el.classBinding = getBindingAttr(el, 'class', false /* getStatic */) const classBinding = getBindingAttr(el, 'class', false /* getStatic */)
if (classBinding) {
el.classBinding = classBinding
}
} }
function processStyleBinding (el) { function processStyleBinding (el) {
el.styleBinding = getBindingAttr(el, 'style', false /* getStatic */) const styleBinding = getBindingAttr(el, 'style', false /* getStatic */)
if (styleBinding) {
el.styleBinding = styleBinding
}
} }
function processTransition (el) { function processTransition (el) {
const transition = getBindingAttr(el, 'transition') let transition = getBindingAttr(el, 'transition')
el.transition = transition === '""' ? true : transition if (transition === '""') {
if (el.transition) { transition = true
}
if (transition) {
el.transition = transition
el.transitionOnAppear = getBindingAttr(el, 'transition-on-appear') != null el.transitionOnAppear = getBindingAttr(el, 'transition-on-appear') != null
} }
} }

Loading…
Cancel
Save