保誠-保戶業務員媒合平台
HelenHuang
2022-06-09 ab4e8129d5c94ff96e6c85d0d2b66a04a052b4e5
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
129
130
131
132
133
134
135
136
137
138
139
140
141
/* @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, 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 = []
 
  let currentOptimizableGroup = []
  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 {
      // 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
    isSelectWithModel(node) // <select v-model> requires runtime inspection
  )
}
 
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))
  )
}
 
// <select v-model> cannot be optimized because it requires a runtime check
// to determine proper selected option
function isSelectWithModel (node: ASTNode): boolean {
  return (
    node.type === 1 &&
    node.tag === 'select' &&
    node.directives != null &&
    node.directives.some(d => d.name === 'model')
  )
}