-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathruntime-with-compiler.ts
121 lines (114 loc) · 3.64 KB
/
runtime-with-compiler.ts
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
import config from 'core/config'
import { warn, cached } from 'core/util/index'
import { mark, measure } from 'core/util/perf'
import Vue from './runtime/index'
import { query } from './util/index'
import { compileToFunctions } from './compiler/index'
import {
shouldDecodeNewlines,
shouldDecodeNewlinesForHref
} from './util/compat'
import type { Component } from 'types/component'
import type { GlobalAPI } from 'types/global-api'
// 通过ID获取模板
const idToTemplate = cached(id => {
const el = query(id)
return el && el.innerHTML
})
const mount = Vue.prototype.$mount
Vue.prototype.$mount = function (
el?: string | Element,
hydrating?: boolean
): Component {
el = el && query(el)
// 不允许挂载到body或者html节点上
/* istanbul ignore if */
if (el === document.body || el === document.documentElement) {
__DEV__ &&
warn(
`Do not mount Vue to <html> or <body> - mount to normal elements instead.`
)
return this
}
const options = this.$options
// 如果不存在render函数则要生成render函数
// 因为这是带编译器的版本,需要再原有mount函数的基础上重写mount函数添加编译render函数的功能
// resolve template/el and convert to render function
if (!options.render) {
let template = options.template
if (template) {
// template是字符串
if (typeof template === 'string') {
// template开头是# 说明传入的是节点ID
if (template.charAt(0) === '#') {
template = idToTemplate(template)
/* istanbul ignore if */
if (__DEV__ && !template) {
warn(
`Template element not found or is empty: ${options.template}`,
this
)
}
}
// 如果传入的是dom节点,有nodeType说明是dom节点
} else if (template.nodeType) {
template = template.innerHTML
} else {
if (__DEV__) {
warn('invalid template option:' + template, this)
}
return this
}
// 没有template的情况下如果有el参数则使用el getOuterHTML作为模板
} else if (el) {
// @ts-expect-error
template = getOuterHTML(el)
}
if (template) {
// 开发模式下开启类性能检测添加编译性能检测
/* istanbul ignore if */
if (__DEV__ && config.performance && mark) {
mark('compile')
}
// 模版编译为render函数
const { render, staticRenderFns } = compileToFunctions(
template,
{
outputSourceRange: __DEV__,
shouldDecodeNewlines,
shouldDecodeNewlinesForHref,
delimiters: options.delimiters,
comments: options.comments
},
this
)
// render函数挂载到options上
options.render = render
// 静态渲染函数
// vue会在编译时把静态部分抽离出来生成一个静态渲染函数数组,并对执行后的渲染结果进行缓存
options.staticRenderFns = staticRenderFns
// 打印编译时长
/* istanbul ignore if */
if (__DEV__ && config.performance && mark) {
mark('compile end')
measure(`vue ${this._name} compile`, 'compile', 'compile end')
}
}
}
return mount.call(this, el, hydrating)
}
/**
* Get outerHTML of elements, taking care
* of SVG elements in IE as well.
*/
function getOuterHTML(el: Element): string {
if (el.outerHTML) {
return el.outerHTML
} else {
const container = document.createElement('div')
container.appendChild(el.cloneNode(true))
return container.innerHTML
}
}
Vue.compile = compileToFunctions
export default Vue as GlobalAPI