forked from vuejs/vue
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathoptimizer.js
More file actions
128 lines (116 loc) · 3.71 KB
/
optimizer.js
File metadata and controls
128 lines (116 loc) · 3.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/* @flow */
/**
* In SSR, the vdom tree is generated only once and never patched, so
* we can optimize most element / trees into plain string render functions.
* The SSR optimizer walks the AST tree to detect optimizable elements and trees.
*
* The criteria for SSR optimizability is quite a bit looser than static tree
* detection (which is designed for client re-render). In SSR we bail only for
* components/slots/custom directives.
*/
import { no, makeMap, isBuiltInTag } from 'shared/util'
// optimizability constants
export const optimizability = {
FALSE: 0, // whole sub tree un-optimizable
FULL: 1, // whole sub tree optimizable
SELF: 2, // self optimizable but has some un-optimizable children
CHILDREN: 3, // self un-optimizable but have fully optimizable children
PARTIAL: 4 // self un-optimizable with some un-optimizable children
}
let isPlatformReservedTag
export function optimize (root: ?ASTElement, 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
}
// root node or nodes with custom directives should always be a VNode
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)
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 = []
let currentOptimizableGroup = []
const pushGroup = () => {
if (currentOptimizableGroup.length) {
optimizedChildren.push({
type: 1,
parent: el,
tag: 'template',
attrsList: [],
attrsMap: {},
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 {
// wrap fully-optimizable adjacent siblings inside a template tag
// so that they can be optimized into a single ssrNode by codegen
pushGroup()
optimizedChildren.push(c)
}
}
pushGroup()
return optimizedChildren
}
function isUnOptimizableTree (node: ASTNode): boolean {
if (node.type === 2 || node.type === 3) { // text or expression
return false
}
return (
isBuiltInTag(node.tag) || // built-in (slot, component)
!isPlatformReservedTag(node.tag) || // custom component
!!node.component // "is" component
)
}
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))
)
}