# 首次加载(编译-parse)
前言
编译首先会通过parse
方法,将 template 模板中的字符串通过正则将其解析,得到指令、class、style 等数据
export function parse(
template: string,
options: CompilerOptions
): ASTElement | void {
warn = options.warn || baseWarn;
platformIsPreTag = options.isPreTag || no;
platformMustUseProp = options.mustUseProp || no;
platformGetTagNamespace = options.getTagNamespace || no;
transforms = pluckModuleFunction(options.modules, "transformNode");
preTransforms = pluckModuleFunction(options.modules, "preTransformNode");
postTransforms = pluckModuleFunction(options.modules, "postTransformNode");
delimiters = options.delimiters;
const stack = [];
const preserveWhitespace = options.preserveWhitespace !== false;
let root;
let currentParent;
let inVPre = false;
let inPre = false;
let warned = false;
function warnOnce(msg) {
if (!warned) {
warned = true;
warn(msg);
}
}
function closeElement(element) {
// check pre state
if (element.pre) {
inVPre = false;
}
if (platformIsPreTag(element.tag)) {
inPre = false;
}
// apply post-transforms
for (let i = 0; i < postTransforms.length; i++) {
postTransforms[i](element, options);
}
}
parseHTML(template, {
warn,
expectHTML: options.expectHTML,
isUnaryTag: options.isUnaryTag,
canBeLeftOpenTag: options.canBeLeftOpenTag,
shouldDecodeNewlines: options.shouldDecodeNewlines,
shouldDecodeNewlinesForHref: options.shouldDecodeNewlinesForHref,
shouldKeepComment: options.comments,
start(tag, attrs, unary) {
// check namespace.
// inherit parent ns if there is one
const ns =
(currentParent && currentParent.ns) || platformGetTagNamespace(tag);
// handle IE svg bug
/* istanbul ignore if */
if (isIE && ns === "svg") {
attrs = guardIESVGBug(attrs);
}
let element: ASTElement = createASTElement(tag, attrs, currentParent);
if (ns) {
element.ns = ns;
}
if (isForbiddenTag(element) && !isServerRendering()) {
element.forbidden = true;
process.env.NODE_ENV !== "production" &&
warn(
"Templates should only be responsible for mapping the state to the " +
"UI. Avoid placing tags with side-effects in your templates, such as " +
`<${tag}>` +
", as they will not be parsed."
);
}
// apply pre-transforms
for (let i = 0; i < preTransforms.length; i++) {
element = preTransforms[i](element, options) || element;
}
if (!inVPre) {
processPre(element);
if (element.pre) {
inVPre = true;
}
}
if (platformIsPreTag(element.tag)) {
inPre = true;
}
if (inVPre) {
processRawAttrs(element);
} else if (!element.processed) {
// structural directives
processFor(element);
processIf(element);
processOnce(element);
// element-scope stuff
processElement(element, options);
}
function checkRootConstraints(el) {
if (process.env.NODE_ENV !== "production") {
if (el.tag === "slot" || el.tag === "template") {
warnOnce(
`Cannot use <${el.tag}> as component root element because it may ` +
"contain multiple nodes."
);
}
if (el.attrsMap.hasOwnProperty("v-for")) {
warnOnce(
"Cannot use v-for on stateful component root element because " +
"it renders multiple elements."
);
}
}
}
// tree management
if (!root) {
root = element;
checkRootConstraints(root);
} else if (!stack.length) {
// allow root elements with v-if, v-else-if and v-else
if (root.if && (element.elseif || element.else)) {
checkRootConstraints(element);
addIfCondition(root, {
exp: element.elseif,
block: element,
});
} else if (process.env.NODE_ENV !== "production") {
warnOnce(
`Component template should contain exactly one root element. ` +
`If you are using v-if on multiple elements, ` +
`use v-else-if to chain them instead.`
);
}
}
if (currentParent && !element.forbidden) {
if (element.elseif || element.else) {
processIfConditions(element, currentParent);
} else if (element.slotScope) {
// scoped slot
currentParent.plain = false;
const name = element.slotTarget || '"default"';
(currentParent.scopedSlots || (currentParent.scopedSlots = {}))[
name
] = element;
} else {
currentParent.children.push(element);
element.parent = currentParent;
}
}
if (!unary) {
currentParent = element;
stack.push(element);
} else {
closeElement(element);
}
},
end() {
// remove trailing whitespace
const element = stack[stack.length - 1];
const lastNode = element.children[element.children.length - 1];
if (lastNode && lastNode.type === 3 && lastNode.text === " " && !inPre) {
element.children.pop();
}
// pop stack
stack.length -= 1;
currentParent = stack[stack.length - 1];
closeElement(element);
},
chars(text: string) {
if (!currentParent) {
if (process.env.NODE_ENV !== "production") {
if (text === template) {
warnOnce(
"Component template requires a root element, rather than just text."
);
} else if ((text = text.trim())) {
warnOnce(`text "${text}" outside root element will be ignored.`);
}
}
return;
}
// IE textarea placeholder bug
/* istanbul ignore if */
if (
isIE &&
currentParent.tag === "textarea" &&
currentParent.attrsMap.placeholder === text
) {
return;
}
const children = currentParent.children;
text =
inPre || text.trim()
? isTextTag(currentParent)
? text
: decodeHTMLCached(text)
: // only preserve whitespace if its not right after a starting tag
preserveWhitespace && children.length
? " "
: "";
if (text) {
let res;
if (!inVPre && text !== " " && (res = parseText(text, delimiters))) {
children.push({
type: 2,
expression: res.expression,
tokens: res.tokens,
text,
});
} else if (
text !== " " ||
!children.length ||
children[children.length - 1].text !== " "
) {
children.push({
type: 3,
text,
});
}
}
},
comment(text: string) {
currentParent.children.push({
type: 3,
text,
isComment: true,
});
},
});
return root;
}
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
← 首次加载(编译) 首次加载(编译-ast) →