由深入浅出 Vue 构建流程可知,当我们使用:
1 | import Vue from 'Vue' |
时,默认查找的文件是 dist/vue.runtime.esm.js
。而构建出这个文件的入口文件是:src/platforms/web/entry-runtime.js
。
runtime 版本是不包含 compiler 的,也就是没有编译 Vue 模板的过程。通常编译的工作交给 vue-loader,也就是 webpack 来代劳。但是从分析源码的角度来看,我们还是有必要要了解一下编译过程。所以我们从带 compiler 的入口开始:
1 | // 源码分析从此开始 |
Vue 是一个构造函数
在 Vue 里,一个简单的 Hello World 程序如下:
1 | <div id="app"> |
1 | var app = new Vue({ |
我们可以注意到一个通常的 Vue 应用程序,是通过 new Vue 开始的。我们来看看 Vue 到底是什么。
由上图的调用流程可知 Vue 的构造函数位于 src/core/instance/index.js
:
1 | import { initMixin } from './init' |
我们绕了这么一大圈(如下图),终于找到了Vue 的原型。这样写有什么好处呢?
这样写最大的好处是功能拆分,可以按功能模块来划分,逐步扩展 Vue 的功能。
比如在 core/index.js
中,我们扩展了 Global API, 在 instance/index.js
中 对 Vue做了很多 mixin。
静态属性,实例属性,和原型属性
Vue 的源码生成的整个过程中,有一个非常重要的点是,将各种工具函数,实例方法等挂载在 Vue 中。
挂载的形式主要有三种
- 静态方法挂载。适用于通用功能,不需要实例化就能使用。
比如 Vue.use 用来初始化插件,Vue.config 用来配置 Vue 的特性。基本上可以对应 api 文档中的 Global API.
1 | // src/core/gloal-api/use.js |
- 原型属性挂载。需要实例化的通用功能。
比如 $on, $off, $nextTick, $watch, $set, $delete 等。通用功能放在原型是一个时间换空间的做法。
项目越大,业务越负杂,内存越节省,而原型查找的效率损失可以忽略不计。
- 实例属性。需要实例化才能使用。
如 vm.$slots等。Vue 在实现过程中还使用了很多内部属性,在整个编码过程中使用。
第二种和第三种挂载形式对应于文档实例属性方法等章节。
以上。
ISSUE
有问题?来 Github 一起讨论。