1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 | import { no, makeMap, isBuiltInTag } from 'shared/util'
|
14 |
|
15 |
|
16 | export const optimizability = {
|
17 | FALSE: 0,
|
18 | FULL: 1,
|
19 | SELF: 2,
|
20 | CHILDREN: 3,
|
21 | PARTIAL: 4
|
22 | }
|
23 |
|
24 | let isPlatformReservedTag
|
25 |
|
26 | export function optimize (root: ?ASTElement, options: CompilerOptions) {
|
27 | if (!root) return
|
28 | isPlatformReservedTag = options.isReservedTag || no
|
29 | walk(root, true)
|
30 | }
|
31 |
|
32 | function walk (node: ASTNode, isRoot?: boolean) {
|
33 | if (isUnOptimizableTree(node)) {
|
34 | node.ssrOptimizability = optimizability.FALSE
|
35 | return
|
36 | }
|
37 |
|
38 | const selfUnoptimizable = isRoot || hasCustomDirective(node)
|
39 | const check = child => {
|
40 | if (child.ssrOptimizability !== optimizability.FULL) {
|
41 | node.ssrOptimizability = selfUnoptimizable
|
42 | ? optimizability.PARTIAL
|
43 | : optimizability.SELF
|
44 | }
|
45 | }
|
46 | if (selfUnoptimizable) {
|
47 | node.ssrOptimizability = optimizability.CHILDREN
|
48 | }
|
49 | if (node.type === 1) {
|
50 | for (let i = 0, l = node.children.length; i < l; i++) {
|
51 | const child = node.children[i]
|
52 | walk(child)
|
53 | check(child)
|
54 | }
|
55 | if (node.ifConditions) {
|
56 | for (let i = 1, l = node.ifConditions.length; i < l; i++) {
|
57 | const block = node.ifConditions[i].block
|
58 | walk(block, isRoot)
|
59 | check(block)
|
60 | }
|
61 | }
|
62 | if (node.ssrOptimizability == null ||
|
63 | (!isRoot && (node.attrsMap['v-html'] || node.attrsMap['v-text']))
|
64 | ) {
|
65 | node.ssrOptimizability = optimizability.FULL
|
66 | } else {
|
67 | node.children = optimizeSiblings(node)
|
68 | }
|
69 | } else {
|
70 | node.ssrOptimizability = optimizability.FULL
|
71 | }
|
72 | }
|
73 |
|
74 | function optimizeSiblings (el) {
|
75 | const children = el.children
|
76 | const optimizedChildren = []
|
77 |
|
78 | let currentOptimizableGroup = []
|
79 | const pushGroup = () => {
|
80 | if (currentOptimizableGroup.length) {
|
81 | optimizedChildren.push({
|
82 | type: 1,
|
83 | parent: el,
|
84 | tag: 'template',
|
85 | attrsList: [],
|
86 | attrsMap: {},
|
87 | rawAttrsMap: {},
|
88 | children: currentOptimizableGroup,
|
89 | ssrOptimizability: optimizability.FULL
|
90 | })
|
91 | }
|
92 | currentOptimizableGroup = []
|
93 | }
|
94 |
|
95 | for (let i = 0; i < children.length; i++) {
|
96 | const c = children[i]
|
97 | if (c.ssrOptimizability === optimizability.FULL) {
|
98 | currentOptimizableGroup.push(c)
|
99 | } else {
|
100 |
|
101 |
|
102 | pushGroup()
|
103 | optimizedChildren.push(c)
|
104 | }
|
105 | }
|
106 | pushGroup()
|
107 | return optimizedChildren
|
108 | }
|
109 |
|
110 | function isUnOptimizableTree (node: ASTNode): boolean {
|
111 | if (node.type === 2 || node.type === 3) {
|
112 | return false
|
113 | }
|
114 | return (
|
115 | isBuiltInTag(node.tag) ||
|
116 | !isPlatformReservedTag(node.tag) ||
|
117 | !!node.component ||
|
118 | isSelectWithModel(node)
|
119 | )
|
120 | }
|
121 |
|
122 | const isBuiltInDir = makeMap('text,html,show,on,bind,model,pre,cloak,once')
|
123 |
|
124 | function hasCustomDirective (node: ASTNode): ?boolean {
|
125 | return (
|
126 | node.type === 1 &&
|
127 | node.directives &&
|
128 | node.directives.some(d => !isBuiltInDir(d.name))
|
129 | )
|
130 | }
|
131 |
|
132 |
|
133 |
|
134 | function isSelectWithModel (node: ASTNode): boolean {
|
135 | return (
|
136 | node.type === 1 &&
|
137 | node.tag === 'select' &&
|
138 | node.directives != null &&
|
139 | node.directives.some(d => d.name === 'model')
|
140 | )
|
141 | }
|