本文适合初次阅读vuejs源码准备阅读的童鞋。由于vuejs源码非常庞大,分布在各个文件夹中,如果想看懂源码,就需要了解清楚整个框架的脉络。本文从编译入口入手,在源码中寻找重点。准备打包源码浏览器调试比单纯阅读源码效率更高,那么vuejs如何添加sourceMap呢?把vue源码仓库fork到自己的github仓库,方便大家随意添加注释和修改。下载项目,打开package.json文件,在文件中找到:vuejsispackagedwithrollup,在dev命令最后加上--sourcemap。执行npmrundev打包生成带有sourcemap的vue文件。找到examples文件夹,随便找一个用例,把vue文件的引用地址改成新打包生成的文件。用浏览器打开html文件,打开控制台,就可以看到源码了。理解打包文件在命令行执行npmrunbuild,会打包所有版本的vue文件,打包结果如下:其中:common表示符合commonjs规范的文件。ems表示符合ESModule规范的文件。dev表示文件内容未压缩且可读。prod表示文件内容被压缩。runtime表示运行版本,不包含模板编译功能。也就是在声明组件的时候template模板不能编译,只能使用render函数。在vue-cli搭建的项目中,由于打包时template模板被编译成render函数,所以打包后引用的vue版本为runtime版本。在vue-cli创建的项目中执行vueinspect>out.js。可以将webpack的所有配置输出到out.js文件中,查看resolve配置可以看到打包后的vue版本:resolve:{alias:{vue$:'vue/dist/vue.runtime.esm.js'}}不是加上common,es表示是umd规范文件。该文件可以支持commonjs、ESModule、AMD,也可以通过window.Vue直接引用。不加rentime就是完整版本,包括runtime和compiler。整体代码比运行时版本多。入口文件vuejs项目的包入口文件可以看作是源码阅读的入口文件。打包时执行如下命令:rollup-w-cscripts/config.js--environmentTARGET:web-full-dev--sourcemap其中scripts/config.js为rollup配置文件路径,rollup配置文件需要export一个对象,其中input属性指定打包入口文件。scripts/config.js在文件末尾:.keys(builds).map(genConfig)}由于执行的打包命令中包含--environmentTARGET:web-full-dev,此时process.env.TARGET的值为web-full-dev,即配置通过genConfig和export获得。在getConfig方法中,通过constopts=builds[name]获取内置配置,其中name为web-full-dev。通过opts.entry指定输入属性值,其最终值为platforms/web/entry-runtime-with-compiler.js。platforms文件plus存放的是平台相关的代码,web文件夹是web相关的代码,weex文件夹是weex相关的代码。platforms/web/entry-runtime-with-compiler.js这个文件的功能并不复杂,只需要修改Vue原型上的$mount方法,增加一个静态方法compile:Vue.prototype.$mount=function(el?:string|Element,hydrating?:boolean):Component{//具体逻辑}//静态方法compileVue.compile=compileToFunctions在原有$mount方法的基础上增加了判断。当vue组件没有定义render时,判断是否传入了一个temple,如果传入了,就编译成render。具体逻辑可以简化为:constoptions=this.$options//ifnorenderif(!options.render){//获取模板lettemplate=options.template//....这里包含各种模板情况判断if(template){//编译模板渲染函数const{render,staticRenderFns}=compileToFunctions(template,{outputSourceRange:process.env.NODE_ENV!=='production',shouldDecodeNewlines,shouldDecodeNewlinesForHref,delimiters:options.delimiters,comments:options.comments},this)//在options上面添加render函数options.render=render//静态render函数,用于优化Dom渲染过程options.staticRenderFns=staticRenderFns}}//调用原来的mount方法returnmount.call(this,el,hydrating)其中compileToFunctions是模板编译的入口,等到后面的编译部分继续。platforms/web/runtime/index.jsentry-runtime-with-compiler.js文件中的Vue类是从platforms/web/runtime/index.js文件导入的。该文件为Vue类添加了特定于Web平台的功能,例如Dom操作。这个文件可以分为三个部分:Extendedconfig//添加一些web平台特有的辅助方法Vue.config.mustUseProp=mustUsePropVue.config.isReservedTag=isReservedTag//判断是否为保留标签,比如inputVue.config.isReservedAttr=isReservedAttr//它是保留属性吗?Vue.config.getTagNamespace=getTagNamespace//获取元素的命名空间Vue.config.isUnknownElement=isUnknownElement这里添加的方法大部分是Vue内部使用的,平时工作很少用到,所以不再详解。Addglobalbuilt-incomponentsanddirectives//添加web平台相关的全局内置组件和指令extend(Vue.options.directives,platformDirectives)extend(Vue.options.components,platformComponents)这里添加的组件有:transition和过渡组。这里添加的指令是:v-model和v-show。添加原型方法添加了两个关键方法:DomMount和DomUpdate。//添加虚拟Dom更新操作Vue.prototype.__patch__=inBrowser?patch:noop//添加挂载方法Vue.prototype.$mount=function(el?:string|Element,hydrating?:boolean):Component{el=el&&inBrowser?query(el):undefined//RendervirtualDomreturnmountComponent(this,el,hydrating)}mountComponent是Vnodes渲染的入口方法,后面会具体化为Vnodes渲染过程。core/index.jsplatforms/web/runtime/index.js中的Vue类是从core/index.js文件中导入的。core文件夹包含vue核心代码,与平台无关。这个文件只包含一个关键代码://给Vue类添加全局静态方法如Vue.extend、Vue.component等。initGlobalAPI(Vue)//...其余为ssr服务端渲染相关的全局属性,这里不再赘述。initGlobalAPI定义在core/global-api/index.js:exportfunctioninitGlobalAPI(Vue:GlobalAPI){//定义配置Object.defineProperty(Vue,'config',configDef)//辅助函数,不要直接使用,vuejs不保证正确执行Vue.util={warn,extend,mergeOptions,defineReactive}//设置全局set、delete和nextTickVue.set=setVue.delete=delVue.nextTick=nextTick//添加可观察方法Vue.observable=
