|
|
@ -1,6 +1,12 @@ |
|
|
|
/* @flow */ |
|
|
|
|
|
|
|
import { no, isBuiltInTag } from 'shared/util' |
|
|
|
import { no, makeMap, isBuiltInTag } from 'shared/util' |
|
|
|
|
|
|
|
// optimizability constants
|
|
|
|
export const FALSE = 0 // whole sub tree un-optimizable
|
|
|
|
export const FULL = 1 // whole sub tree optimizable
|
|
|
|
export const PARTIAL = 2 // self optimizable but has un-optimizable children
|
|
|
|
export const CHILDREN = 3 // self un-optimizable but may have optimizable children
|
|
|
|
|
|
|
|
let isPlatformReservedTag |
|
|
|
|
|
|
@ -16,70 +22,60 @@ let isPlatformReservedTag |
|
|
|
export function optimize (root: ?ASTElement, options: CompilerOptions) { |
|
|
|
if (!root) return |
|
|
|
isPlatformReservedTag = options.isReservedTag || no |
|
|
|
// first pass: mark all non-optimizable nodes.
|
|
|
|
markNonOptimizable(root) |
|
|
|
// second pass: mark optimizable trees.
|
|
|
|
markOptimizableTrees(root, false) |
|
|
|
walk(root, true) |
|
|
|
} |
|
|
|
|
|
|
|
function markNonOptimizable (node: ASTNode) { |
|
|
|
node.ssrOptimizable = isOptimizable(node) |
|
|
|
if (node.type === 1) { |
|
|
|
// do not make component slot content optimizable so that render fns can
|
|
|
|
// still manipulate the nodes.
|
|
|
|
if ( |
|
|
|
!isPlatformReservedTag(node.tag) && |
|
|
|
node.tag !== 'slot' && |
|
|
|
node.attrsMap['inline-template'] == null |
|
|
|
) { |
|
|
|
function walk (node: ASTNode, isRoot?: boolean) { |
|
|
|
if (isUnOptimizableTree(node)) { |
|
|
|
node.ssrOptimizability = FALSE |
|
|
|
return |
|
|
|
} |
|
|
|
// root node or nodes with custom directives should always be a VNode
|
|
|
|
if (isRoot || hasCustomDirective(node)) { |
|
|
|
node.ssrOptimizability = CHILDREN |
|
|
|
} |
|
|
|
if (node.type === 1) { |
|
|
|
for (let i = 0, l = node.children.length; i < l; i++) { |
|
|
|
const child = node.children[i] |
|
|
|
markNonOptimizable(child) |
|
|
|
if (!child.ssrOptimizable) { |
|
|
|
node.ssrOptimizable = false |
|
|
|
walk(child) |
|
|
|
if (child.ssrOptimizability !== FULL && node.ssrOptimizability == null) { |
|
|
|
node.ssrOptimizability = PARTIAL |
|
|
|
} |
|
|
|
} |
|
|
|
if (node.ifConditions) { |
|
|
|
for (let i = 1, l = node.ifConditions.length; i < l; i++) { |
|
|
|
const block = node.ifConditions[i].block |
|
|
|
markNonOptimizable(block) |
|
|
|
if (!block.ssrOptimizable) { |
|
|
|
node.ssrOptimizable = false |
|
|
|
walk(block) |
|
|
|
if (block.ssrOptimizability !== FULL && node.ssrOptimizability == null) { |
|
|
|
node.ssrOptimizability = PARTIAL |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (node.ssrOptimizability == null) { |
|
|
|
node.ssrOptimizability = FULL |
|
|
|
} |
|
|
|
} else { |
|
|
|
node.ssrOptimizability = FULL |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
function isOptimizable (node: ASTNode): boolean { |
|
|
|
function isUnOptimizableTree (node: ASTNode): boolean { |
|
|
|
if (node.type === 2 || node.type === 3) { // text or expression
|
|
|
|
return true |
|
|
|
return false |
|
|
|
} |
|
|
|
return ( |
|
|
|
!isBuiltInTag(node.tag) && // not a built-in (slot, component)
|
|
|
|
!!isPlatformReservedTag(node.tag) // not a component
|
|
|
|
isBuiltInTag(node.tag) || // built-in (slot, component)
|
|
|
|
!isPlatformReservedTag(node.tag) // custom component
|
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
function markOptimizableTrees (node: ASTNode) { |
|
|
|
if (node.type === 1) { |
|
|
|
if (node.ssrOptimizable) { |
|
|
|
node.ssrOptimizableRoot = true |
|
|
|
return |
|
|
|
} else { |
|
|
|
node.ssrOptimizableRoot = false |
|
|
|
} |
|
|
|
if (node.children) { |
|
|
|
for (let i = 0, l = node.children.length; i < l; i++) { |
|
|
|
markOptimizableTrees(node.children[i]) |
|
|
|
} |
|
|
|
} |
|
|
|
if (node.ifConditions) { |
|
|
|
for (let i = 1, l = node.ifConditions.length; i < l; i++) { |
|
|
|
markOptimizableTrees(node.ifConditions[i].block) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
// only need to check built-in dirs with runtime
|
|
|
|
const isBuiltInDir = makeMap('model,show') |
|
|
|
|
|
|
|
function hasCustomDirective (node: ASTNode): ?boolean { |
|
|
|
return ( |
|
|
|
node.type === 1 && |
|
|
|
node.directives && |
|
|
|
node.directives.some(d => !isBuiltInDir(d.name)) |
|
|
|
) |
|
|
|
} |
|
|
|