- A+
前言:深入了解 Vue 源码的时候,new Vue() 创建一个 Vue 实例就是最好的入口。只要我们了解这个函数具体做了什么事情,也就对 Vue 的底层实现有了基础的了解。
寻找 Vue 构造函数
Vue 项目源码构建一个 Vue.js 版本,使用是 rollup,具体的 npm 脚本语句我们可以在项目根目录的 packjson.json
的 script
命令里面看到:
"scripts": { "dev": "rollup -w -c scripts/config.js --environment TARGET:web-full-dev", "dev:cjs": "rollup -w -c scripts/config.js --environment TARGET:web-runtime-cjs-dev", "dev:esm": "rollup -w -c scripts/config.js --environment TARGET:web-runtime-esm", "dev:test": "karma start test/unit/karma.dev.config.js", "dev:ssr": "rollup -w -c scripts/config.js --environment TARGET:web-server-renderer", "dev:compiler": "rollup -w -c scripts/config.js --environment TARGET:web-compiler ", ... },
现在我们以 web 平台下的完整版构建,也就是 npm run dev
为切入点,对应的 script 命令就是:
"dev": "rollup -w -c scripts/config.js --environment TARGET:web-full-dev"
什么是完整版构建呢?完整版构建是相对于运行版构建而言的,两者关系可以用一个公式来描述:
运行时版 + Compiler = 完整版
。所以,完整版就是比运行时版多了一个 Compiler 编译的过程。那什么是 Compiler 编译呢?可以简单理解为字符串模板 template 编译为 render 渲染函数的这个过程。完整版的Vue是把这个过程放到了代码执行阶段,而运行时版则是放到了项目打包构建阶段。
我们学习源码当然要学习得更加全面为好,所以在这里选择完整版的构建去学习。
根据命令含义,我们在 scripts/config.js
文件里面找到:
'web-full-dev': { entry: resolve('web/entry-runtime-with-compiler.js'), dest: resolve('dist/vue.js'), format: 'umd', env: 'development', alias: { he: './entity-decoder' }, banner },
最后,我们发现入口文件就是 web/entry-runtime-with-compiler.js
。这个文件最后执行的代码是
export default Vue
这个就是我们能拿到的 Vue 构造函数。但是这不是终点,因为我们发现这个文件开头还有一句:
import Vue from './runtime/index'
说明 Vue 构造是从这个文件里面来的,我们继续进入这个文件去看,又发现:
import Vue from 'core/index'
继续到这个文件,又发现:
import Vue from './instance/index'
所以,还得继续到这个文件里面,到这里,我们终于发现 Vue 构造函数的定义了
function Vue (options) { if (process.env.NODE_ENV !== 'production' && !(this instanceof Vue) ) { warn('Vue is a constructor and should be called with the `new` keyword') } this._init(options) }
是不是有点失望,找了那么久,构造函数才这么点。
其实不是的,这个只是一开始的 Vue 构造函数,而在我们一路找来的那么多个 js 文件,都是在对这个 Vue 构造函数进行进一步的处理,一步一步处理后,在 web/entry-runtime-with-compiler.js
才得到我们开发者常见的 Vue 构造函数。
而这些 js 文件都具体对 Vue 构造函数做了什么呢,下面这张图可以简单的描述一下:
好的,现在我们已经知道 Vue 构造函数大概长什么样子了,那么接下来就需要知道 Vue 构造函数是怎么创建一个 Vue 实例的了:创建Vue实例二:Vue.prototype._init ;