我们知道 src/platforms/web Vue 编译的入口,主要进行分析运行时版本(不携带编译器) entry-runtime.js 和编译器版本(携带编译器) entry-runtime-with-compiler.js 接下来我们看下它们的代码。

运行时(entry-runtime.js)

  1. import Vue from './runtime/index';
  2. export default Vue;

运行时版本的代码很精简,主要就是在 src/platforms/web/runtime/index.js 导入了 Vue 然后导出 Vue

编译器(entry-runtime-with-compiler.js)

  1. import config from 'core/config';
  2. import { warn, cached } from 'core/util/index';
  3. import { mark, measure } from 'core/util/perf';
  4. import Vue from './runtime/index';
  5. import { query } from './util/index';
  6. import { compileToFunctions } from './compiler/index';
  7. import { shouldDecodeNewlines, shouldDecodeNewlinesForHref } from './util/compat';
  8. const idToTemplate = cached((id) => {
  9. const el = query(id);
  10. return el && el.innerHTML;
  11. });
  12. const mount = Vue.prototype.$mount;
  13. Vue.prototype.$mount = function (el?: string | Element, hydrating?: boolean): Component {
  14. el = el && query(el);
  15. /* istanbul ignore if */
  16. if (el === document.body || el === document.documentElement) {
  17. process.env.NODE_ENV !== 'production' && warn(`Do not mount Vue to <html> or <body> - mount to normal elements instead.`);
  18. return this;
  19. }
  20. const options = this.$options;
  21. // resolve template/el and convert to render function
  22. if (!options.render) {
  23. let template = options.template;
  24. if (template) {
  25. if (typeof template === 'string') {
  26. if (template.charAt(0) === '#') {
  27. template = idToTemplate(template);
  28. /* istanbul ignore if */
  29. if (process.env.NODE_ENV !== 'production' && !template) {
  30. warn(`Template element not found or is empty: ${options.template}`, this);
  31. }
  32. }
  33. } else if (template.nodeType) {
  34. template = template.innerHTML;
  35. } else {
  36. if (process.env.NODE_ENV !== 'production') {
  37. warn('invalid template option:' + template, this);
  38. }
  39. return this;
  40. }
  41. } else if (el) {
  42. template = getOuterHTML(el);
  43. }
  44. if (template) {
  45. /* istanbul ignore if */
  46. if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
  47. mark('compile');
  48. }
  49. const { render, staticRenderFns } = compileToFunctions(
  50. template,
  51. {
  52. outputSourceRange: process.env.NODE_ENV !== 'production',
  53. shouldDecodeNewlines,
  54. shouldDecodeNewlinesForHref,
  55. delimiters: options.delimiters,
  56. comments: options.comments,
  57. },
  58. this
  59. );
  60. options.render = render;
  61. options.staticRenderFns = staticRenderFns;
  62. /* istanbul ignore if */
  63. if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
  64. mark('compile end');
  65. measure(`vue ${this._name} compile`, 'compile', 'compile end');
  66. }
  67. }
  68. }
  69. return mount.call(this, el, hydrating);
  70. };
  71. /**
  72. * Get outerHTML of elements, taking care
  73. * of SVG elements in IE as well.
  74. */
  75. function getOuterHTML(el: Element): string {
  76. if (el.outerHTML) {
  77. return el.outerHTML;
  78. } else {
  79. const container = document.createElement('div');
  80. container.appendChild(el.cloneNode(true));
  81. return container.innerHTML;
  82. }
  83. }
  84. Vue.compile = compileToFunctions;
  85. export default Vue;

携带编译器版本的代码在运行时的基础上,额外多出来了 90 多行的代码(仅限本文件)。主要的作用就是将 el 转换为 template 字符串,然后再将 template 转换为 render 函数。这里只作为简单介绍,后面将会深入介绍。