vue源码入口文件分析(推荐)
开发vue项目有段时间了,之前用angularjs后来用reactjs但是那时候一直没有时间把自己看源码的思考记录下来,现在我不想再浪费这来之不易的思考,我要坚持!!
看源码我个人感觉非常开心,每每看上一段,自己就充实许多,不知道你是否和我一样。
vue源码是众多module(模块)用rollup工具合并而成,从package.json中能够看到。现在让我们从github上下载vue项目,开始我们今天的“思考”。
我下载的源码版本是:"version":"2.5.7",
源码起始位置从这里可以看到
"dev":"rollup-w-cbuild/config.js--environmentTARGET:web-full-dev" //从build/config.js中找到TARGET:web-full-dev这是运行和编译(支持现在的浏览器,由于里面大量应用了ES6-7)后的 //Runtime+compilerdevelopmentbuild(Browser) '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",然后我们一路找Vue对象终于在“instance/index.js”中找到了:
//这是Vue的开始位置 functionVue(options){ //判断如果是不是生产环境,且不是通过new关键字来创建对象的话,就在控制台打印一个warning if(process.env.NODE_ENV!=='production'&& !(thisinstanceofVue) ){ warn('Vueisaconstructorandshouldbecalledwiththe`new`keyword') } this._init(options) }
看似到这里都结束了,因为我们目的就是找到开始位置,但是我有个疑问,为什么Vue需要这么多层?
entry-runtime-with-compiler.js -> runtime/index.js -> core/index.js -> instance/index.js
当我仔细看了源码后恍然大悟,我们先看看他们这些文件都做了什么:
(1)instance/index.js
从Vue模块命名中能看出一些端倪,instance(实例)。
这个文件是Vue对象的开始,同时也是Vue原型链(prototype)方法的集中文件
//_init initMixin(Vue) //$set、$delete、$watch stateMixin(Vue) //$on、$once、$off、$emit eventsMixin(Vue) //_update、$forceUpdate、$destroy lifecycleMixin(Vue) //$nextTick、_render、以及多个内部调用的方法 renderMixin(Vue)
这些方法只有实例化了才能调用。
(2)core/index.js
这个文件在Instance/index.js创建和初步加工后,再次加工。那他主要做了什么呢?我们不考虑运行环境
initGlobalAPI(Vue)
对,就调用了这个方法,很简单明了吧---"初始化全局接口",
让我们走进initGlobalAPI方法
exportfunctioninitGlobalAPI(Vue:GlobalAPI){ //config constconfigDef={} configDef.get=()=>config //在非生产环境,如何修改了配置文件config里面的内容会提示警告 if(process.env.NODE_ENV!=='production'){ configDef.set=()=>{ warn( 'DonotreplacetheVue.configobject,setindividualfieldsinstead.' ) } } //定义config属性,监听变化 Object.defineProperty(Vue,'config',configDef) //exposedutilmethods. //NOTE:thesearenotconsideredpartofthepublicAPI-avoidrelyingon //themunlessyouareawareoftherisk. Vue.util={ warn, extend, mergeOptions, defineReactive } Vue.set=set Vue.delete=del Vue.nextTick=nextTick Vue.options=Object.create(null) //给vue创建ASSET_TYPES的空对象 ASSET_TYPES.forEach(type=>{ Vue.options[type+'s']=Object.create(null) }) //thisisusedtoidentifythe"base"constructortoextendallplain-object //componentswithinWeex'smulti-instancescenarios. Vue.options._base=Vue extend(Vue.options.components,builtInComponents) //Vue.use initUse(Vue) //Vue.mixin initMixin(Vue) //Vue.extend initExtend(Vue) //Vue.component,Vue.directive,Vue.filter initAssetRegisters(Vue) }
这里面基本都是静态方法,即:用Vue.xxx的形式调用。
(3)runtime/index.js
这里就加一些扩展和在Vue.prototype上添加了__patch__和$mount(挂载元素)。
//Vue.options.directives(model和show)和Vue.options.components(Transition和TransitionGroup) extend(Vue.options.directives,platformDirectives) extend(Vue.options.components,platformComponents) //installplatformpatchfunction Vue.prototype.__patch__=inBrowser?patch:noop //publicmountmethod Vue.prototype.$mount=function( el?:string|Element, hydrating?:boolean ):Component{ el=el&&inBrowser?query(el):undefined returnmountComponent(this,el,hydrating) }
(4)entry-runtime-with-compiler.js
就干了一件事就是重写$mount,Vue根据不同运行环境,重写不同$mount
constmount=Vue.prototype.$mount Vue.prototype.$mount=function( el?:string|Element, hydrating?:boolean ):Component{ ... returnmount.call(this,el,hydrating) }
总结:
到此我们找到了开始执行的文件,和每个文件有什么用,具体怎么做的,做了什么我会下次再写。不过我们刚开始不要太在乎每个细节,不要非得弄懂每一行代码,如果那样,真的太累了,而且可能没有勇气坚持下去。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。