import { no, makeMap, isBuiltInTag } from 'shared/util'
import { ASTElement, ASTNode, CompilerOptions } from 'types/compiler'
export const optimizability = {
FALSE: 0,
FULL: 1,
SELF: 2,
CHILDREN: 3,
PARTIAL: 4
}
let isPlatformReservedTag
export function optimize(root: ASTElement | null, options: CompilerOptions) {
if (!root) return
isPlatformReservedTag = options.isReservedTag || no
walk(root, true)
}
function walk(node: ASTNode, isRoot?: boolean) {
if (isUnOptimizableTree(node)) {
node.ssrOptimizability = optimizability.FALSE
return
}
const selfUnoptimizable = isRoot || hasCustomDirective(node)
const check = child => {
if (child.ssrOptimizability !== optimizability.FULL) {
node.ssrOptimizability = selfUnoptimizable
? optimizability.PARTIAL
: optimizability.SELF
}
}
if (selfUnoptimizable) {
node.ssrOptimizability = optimizability.CHILDREN
}
if (node.type === 1) {
for (let i = 0, l = node.children.length; i < l; i++) {
const child = node.children[i]
walk(child)
check(child)
}
if (node.ifConditions) {
for (let i = 1, l = node.ifConditions.length; i < l; i++) {
const block = node.ifConditions[i].block
walk(block, isRoot)
check(block)
}
}
if (
node.ssrOptimizability == null ||
(!isRoot && (node.attrsMap['v-html'] || node.attrsMap['v-text']))
) {
node.ssrOptimizability = optimizability.FULL
} else {
node.children = optimizeSiblings(node)
}
} else {
node.ssrOptimizability = optimizability.FULL
}
}
function optimizeSiblings(el) {
const children = el.children
const optimizedChildren: any[] = []
let currentOptimizableGroup: any[] = []
const pushGroup = () => {
if (currentOptimizableGroup.length) {
optimizedChildren.push({
type: 1,
parent: el,
tag: 'template',
attrsList: [],
attrsMap: {},
rawAttrsMap: {},
children: currentOptimizableGroup,
ssrOptimizability: optimizability.FULL
})
}
currentOptimizableGroup = []
}
for (let i = 0; i < children.length; i++) {
const c = children[i]
if (c.ssrOptimizability === optimizability.FULL) {
currentOptimizableGroup.push(c)
} else {
pushGroup()
optimizedChildren.push(c)
}
}
pushGroup()
return optimizedChildren
}
function isUnOptimizableTree(node: ASTNode): boolean {
if (node.type === 2 || node.type === 3) {
return false
}
return (
isBuiltInTag(node.tag) ||
!isPlatformReservedTag(node.tag) ||
!!node.component ||
isSelectWithModel(node)
)
}
const isBuiltInDir = makeMap('text,html,show,on,bind,model,pre,cloak,once')
function hasCustomDirective(node: ASTNode): boolean {
return (node.type === 1 &&
node.directives &&
node.directives.some(d => !isBuiltInDir(d.name))) as any
}
function isSelectWithModel(node: ASTNode): boolean {
return (
node.type === 1 &&
node.tag === 'select' &&
node.directives != null &&
node.directives.some(d => d.name === 'model')
)
}