开启compile
在分析完响应式原理后,让我们接着vue源码八()链接继续分析,上次说到,在$mount内部,在没有render函数的情况下,会将template进行一系列操作后,最后对这个template执行compileToFunctions操作,因此我们从compileToFunctions开始分析,
compileToFunctions的查找
这是来自src\platforms\web\entry-runtime-with-compiler.js Vue.prototype.$mount内部的
// 这里对拿到的template进行编译
if (template) {
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
mark('compile')
}
// 如果是模板字符串,需要编译器去编译 也就是进入compileToFunctions这个函数
// 可以通过这个函数查看编译器的工作机制,也就是把template转换为render
const { render, staticRenderFns } = compileToFunctions(template, {
outputSourceRange: process.env.NODE_ENV !== 'production',
shouldDecodeNewlines,
shouldDecodeNewlinesForHref,
delimiters: options.delimiters,
comments: options.comments
}, this)
// 赋值给当前选项的render
options.render = render
options.staticRenderFns = staticRenderFns
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
mark('compile end')
measure(`vue ${this._name} compile`, 'compile', 'compile end')
}
}
可以看到这里执行了compileToFunctions,传入的参数为template和一个对象
createCompileToFunctionFn
因此来分析compileToFunctions,经过一系列文件跳转查找(这里就是看引入和ctrl+左键),来到了src\compiler\to-function.js
export function createCompileToFunctionFn (compile: Function): Function {
// 创建一个空对象
const cache = Object.create(null)
// compileToFunctions中传入的options:
// template,
// {
// outputSourceRange: process.env.NODE_ENV !== 'production',
// shouldDecodeNewlines,
// shouldDecodeNewlinesForHref,
// delimiters: options.delimiters,
// comments: options.comments
// },
// this
return function compileToFunctions (
template: string, // 字符串模板 template 也就是经过那些操作获取之后的template
options?: CompilerOptions, // 参数
vm?: Component // 虚拟dom
): CompiledFunctionResult {
// 把options和空对象混合,也就是获取options,相当于浅拷贝一份options
options = extend({}, options)
// 获取警告
const warn = options.warn || baseWarn
// 删除options.warn属性
delete options.warn
/* istanbul ignore if */
// 忽略
if (process.env.NODE_ENV !== 'production') {
// detect possible CSP restriction
try {
new Function('return 1')
} catch (e) {
if (e.toString().match(/unsafe-eval|CSP/)) {
warn(
'It seems you are using the standalone build of Vue.js in an ' +
'environment with Content Security Policy that prohibits unsafe-eval. ' +
'The template compiler cannot work in this environment. Consider ' +
'relaxing the policy to allow unsafe-eval or pre-compiling your ' +
'templates into render functions.'
)
}
}
}
// check cache
// options中是否有delimiters 一般的delimiters都是delimiters: ['${', '}']这种
const key = options.delimiters
// 如果有delimiters String(['${', '}'])返回 '${,}' + template
? String(options.delimiters) + template
// 如果没有delimiters
: template
// 如果cache对象中有此key属性,直接返回
if (cache[key]) {
return cache[key]
}
// compile 路径:src\compiler\create-compiler.js
// 执行compiled 传入template和options参数
const compiled = compile(template, options)
// 忽略
}
}
options和extend
将options与空对象混合,形成新的options
options = extend({}, options)
此时的options是$mount中传入的一个对象
{
outputSourceRange: process.env.NODE_ENV !== 'production',
shouldDecodeNewlines,
shouldDecodeNewlinesForHref,
delimiters: options.delimiters,
comments: options.comments
}
其中涉及到extend 路径:src\shared\util.js
/**
* Mix properties into target object.
* 将属性混合到目标对象中。
*/
export function extend (to: Object, _from: ?Object): Object {
// 把from中的所有枚举属性添加到to对象中,混合
for (const key in _from) {
to[key] = _from[key]
}
return to
}
获取warn并删除options.warn属性
// 获取警告
const warn = options.warn || baseWarn
// 删除options.warn属性
delete options.warn
检测options中是否有delimeters
// options中是否有delimiters 一般的delimiters都是delimiters: ['${', '}']这种
const key = options.delimiters
// 如果有delimiters String(['${', '}'])返回 '${,}' + template
? String(options.delimiters) + template
// 如果没有delimiters
: template
// 如果cache对象中有此key属性,直接返回
if (cache[key]) {
return cache[key]
}
这是随着vm.options.delimeters传过来的,也就是vue中的options:delimeters,其功能是:改变纯文本插入分隔符。
示例:
new Vue({
delimiters: ['${', '}']
})
因此这一步就是对delimiter进行判断,是否传入了delimeters。传入了就执行String()这个操作,String([’ {,}’ + template,否则就返回原始的template
执行compile
此时执行compile,compile是一个函数参数,来自src\compiler\create-compiler.js
// compile 路径:src\compiler\create-compiler.js
// 执行compiled 传入template和options参数
const compiled = compile(template, options)
总结
下一期分析compile