我们知道 src/platforms/web 是 Vue 编译的入口,主要进行分析运行时版本(不携带编译器) entry-runtime.js 和编译器版本(携带编译器) entry-runtime-with-compiler.js 接下来我们看下它们的代码。
运行时(entry-runtime.js)
import Vue from './runtime/index';
export default Vue;
运行时版本的代码很精简,主要就是在 src/platforms/web/runtime/index.js 导入了 Vue 然后导出 Vue。
编译器(entry-runtime-with-compiler.js)
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';
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);
/* istanbul ignore if */
if (el === document.body || el === document.documentElement) {
process.env.NODE_ENV !== 'production' && warn(`Do not mount Vue to <html> or <body> - mount to normal elements instead.`);
return this;
}
const options = this.$options;
// resolve template/el and convert to render function
if (!options.render) {
let template = options.template;
if (template) {
if (typeof template === 'string') {
if (template.charAt(0) === '#') {
template = idToTemplate(template);
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && !template) {
warn(`Template element not found or is empty: ${options.template}`, this);
}
}
} else if (template.nodeType) {
template = template.innerHTML;
} else {
if (process.env.NODE_ENV !== 'production') {
warn('invalid template option:' + template, this);
}
return this;
}
} else if (el) {
template = getOuterHTML(el);
}
if (template) {
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
mark('compile');
}
const { render, staticRenderFns } = compileToFunctions(
template,
{
outputSourceRange: process.env.NODE_ENV !== 'production',
shouldDecodeNewlines,
shouldDecodeNewlinesForHref,
delimiters: options.delimiters,
comments: options.comments,
},
this
);
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');
}
}
}
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;
携带编译器版本的代码在运行时的基础上,额外多出来了 90 多行的代码(仅限本文件)。主要的作用就是将 el 转换为 template 字符串,然后再将 template 转换为 render 函数。这里只作为简单介绍,后面将会深入介绍。