本文为开始学习vue源码的思路整理。在拿到vue项目源码的之后看到那些项目中的文件夹,会很困惑,不知道每个文件夹内的世界,怎么变换,怎样的魔力,最后产生了vue框架。学习源码也无从学起。我解决了这些困惑之后,形成了这篇文章----vue源码学习入门。文章会根据我自己的学习思路,理清vue项目的大体框架。文章先介绍vue项目中各个文件夹中内包含的功能,然后是从package.json文件开始我们的寻找vue构造函数之旅,最后再从vue构造函数返回入口,看看旅程中的各个节点都为vue加了什么“戏”。

一、Vue项目结构

在GitHub中下载vue项目的源码后解压我们会得到如下的目录。

每个文件夹是做什么的,在项目中的CONTRIBUTING有介绍。我翻译了一下,形成了以下脑图:

我们源码学习,学习的是vue框架内容的源码,而项目中包含的许多构建vuejs的配置文件和辅助vue代码编写的功能模块是我们几乎接触不到的。

我们需要着重注意的是,包含vue源码的【src】文件夹。我把src的内容单独整理,形成了又一脑图,如下:

现在我们大致知道vue项目的各个文件夹的用处了。而且,对于我们需要着重关注的源码src也大致掌握了每个文件夹负责的功能模块。接下来,我们就要开始啃食vue源码了。做一只饥渴的寄生虫吧~

二、寻找构造函数之旅

要了解一个前端项目,一般情况下我们都可以从查看项目的package.json文件开始。从package.json我们可以知道项目有哪些依赖包,定义了哪些脚本字段。其实在CONTRIBUTING中还提到了常用的npm命令。以下是我的截图:

其中提及可以用npm run dev来达到监控和自动重建dist目录下的vue.js文件以及还有一些npm命令在package.json的script中,大家可以按需执行。

那我们找到vue项目中的package.json,看看npm run dev执行了什么命令

rollup指的是一个专注于es6模块构建的工具,会对其构建的代码进行tree-shaking,是tree-shaking的提出者。它与webpack的区别是rollup没做uplify,其构建后的代码尽量保持源代码的样子。

rollup -c指定配置文件为build/config.js,最后将TARGET的值设置成web-full-dev。

打开build文件夹下的config.js。简化后代码如下:

const builds = {...// Runtime+compiler development build (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}...
}function genConfig (name) {const opts = builds[name]const config = {input: opts.entry,external: opts.external,plugins: [replace({__WEEX__: !!opts.weex,__WEEX_VERSION__: weexVersion,__VERSION__: version}),flow(),buble(),alias(Object.assign({}, aliases, opts.alias))].concat(opts.plugins || []),output: {file: opts.dest,format: opts.format,banner: opts.banner,name: opts.moduleName || 'Vue'}}if (opts.env) {config.plugins.push(replace({'process.env.NODE_ENV': JSON.stringify(opts.env)}))}Object.defineProperty(config, '_name', {enumerable: false,value: name})return config
}if (process.env.TARGET) {module.exports = genConfig(process.env.TARGET)
} else {exports.getBuild = genConfigexports.getAllBuilds = () => Object.keys(builds).map(genConfig)
}

我们可以看出,该js中包含着一个builds常量对象,对象的属性名为之前package.json中npm对应命里里设置的TAGET值。js的最后根据是否有TAGET值返回不同的值。我们npm run dev的命令对应的是:

module.exports = genConfig({entry: resolve('web/entry-runtime-with-compiler.js'),dest: resolve('dist/vue.js'),format: 'umd',env: 'development',alias: { he: './entity-decoder' },banner});

并最终返回一个config对象,也就是执行rollup的配置对象。

从builds对象中可以知道,vue的入口文件为:web/entry-runtime-with-compiler.js。在项目结构的介绍中,我们也提及了dist、build的入口文件在platform中。在经过resolve函数之后,路径就是:\vue-dev\src\platforms\web\entry-runtime-with-compiler.js。

打开这个文件,在import中看到了Vue又来自./runtime/index即\vue-dev\src\platforms\web\runtime\index.js。按照这个Vue是来自于import的套路我们接着又找到了core/index.js、instance/index.js。拨开层层迷雾,终识庐山真面目,最终找到了最终的vue构造函数,如下:(\vue-dev\src\core\instance\index.js)

1 function Vue (options) {
2   if (process.env.NODE_ENV !== 'production' &&
3     !(this instanceof Vue)
4   ) {
5     warn('Vue is a constructor and should be called with the `new` keyword')
6   }
7   this._init(options)
8 }

所以寻找Vue构造函数之旅如下图:

三、回首来路,旅程给Vue加了哪些戏

  如果直接从Vue实例化开始阅读源码(一般思路)在阅读的过程中常常会遇见一些没有见过的属性和方法。心中就会产生疑惑,这些属性的值是啥,在哪赋值定义的。为了解决这个疑问,本节通过“回顾旅程”,其实也是vuejs执行顺序,来看看程序对Vue构造函数都加了哪些“戏”。

  Vue(options)作为函数本质上也是一个对象。作为构造函数其原型对象将会对实例产生影响。所以整理出了vuejs执行时挂载在函数上和函数原型上的属性方法有哪些。

vue的构造函数的文件在\vue-dev\src\core\instance\index.js,源码如下:

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)
}initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)export default Vue

vue构造函数先是做一个安全模式的处理,告诉使用者必须通过new字符串调用Vue方法,然后用了一个_init(options)方法。可以推断出_init方法是在Vue原型对象上的方法。

构造函数之外还执行了许多从几个依赖中引入的函数,并将构造函数作为参数传入方法。整理过后再instance/index.js中对Vue以及Vue原型的改变如下:

往上一层core/index.js中,这个js导入了已经在原型上挂载了方法合属性后的Vue,然后导入initGlobalAPI为Vue导入许多全局API(我们在阅读vue官方文档中API分为全局配置、全局API以及实例属性等全局API正是这时导入的)。initGlobalAPI中最后调用依赖引入的initUse、initMixin、initExtend、initAssetRegisters等方法

然后和在Vue原型对象上定义$isServer、$ssrContext两个访问器属性和为Vue添加version属性。具体添加见下图:

再往回看,我们回到runtime/index.js。这个js显示为Vue下的config属性添加属性和赋值,再是将平台相关的directives和components扩展给Vue.options下的directives和components中也就是安装平台特有的指令和组件。

然后为判断是否在浏览器中,如果是就为Vue原型对象安装平台patch功能。接着定义公共的$mount方法。

Vue.prototype.$mount = function (el?: string | Element,hydrating?: boolean
): Component {el = el && inBrowser ? query(el) : undefinedreturn mountComponent(this, el, hydrating)
}

$mount方法先是根据是否在浏览器决定是否query(el),最后都将参数传给core/instance/lifecycle.js中的mountComponent方法,该方法负责挂载更新组件。

具体添加如下:

最后是runtime/entry-runtime-with-compiler.js,这个文件首先是缓存原型对象中存在的$mount方法,然后用一个可以将template/el转化为render函数的方法覆盖原型对象的$mount方法。然后定义了Vue.compile属性为compileToFunctions 函数。这个函数的作用就是将模板 template 编译为render函数。如下图所示:

汇总一下:

第一步:instance/index.js 为Vue.prototype定义实例属性、实例方法/数据、实例方法/事件以及生命周期等实例相关的属性方法。

第二步:core/index.js  主要是通过initGlobalAPI挂载平台相关的全局API 和Vue需要用到的工具函数

第三部:runtime/index.js   是添加平台相关的指令、组件和配置参数和$mount方法

第四部    runtime/entry-runtime-with-compiler.js 给Vue添加了可以支持template的$mount方法和compiler编译器。

回首之旅结束,希望你得到你想得到的。

如此一路走来,我想我们应该是知道vue源码学习的大致框架了。知道了去哪找对应功能模块的代码,以及vue对象上的属性和vue原型对象上的属性有粗略的了解。如果遇见也知道要去哪认识他们,而不是带着苦恼前行了。

希望能帮到你~

注:本文章中学习的源码版本为vue  2.5.2. 文章中涉及的观点和理解均是个人的理解,如有偏颇或是错误还请大神指出,不吝赐教,万分感谢~

转载于:https://www.cnblogs.com/mlFronter/p/7730042.html

vue源码学习--vue源码学习入门相关推荐

  1. vue filter对象_学习vue源码(3) 手写Vue.directive、Vue.filter、Vue.component方法

    一.Vue.directive Vue.directive(id,[definition]); 1)参数 { string } id{ Function | Object } [ definition ...

  2. 学习vue源码(14)深入学习diff

    大白话简述 这一节,先对diff进行简单的描述,不会出现任何的源码,只是为了帮助大家建立一种思路,了解下 Diff 的大概内容. 1.Diff 的作用2.Diff 的做法3.Diff 的比较逻辑4.简 ...

  3. 学习vue源码(14)就慢慢由表入里学习diff

    大白话简述 这一节,先对diff进行简单的描述,不会出现任何的源码,只是为了帮助大家建立一种思路,了解下 Diff 的大概内容. 1.Diff 的作用2.Diff 的做法3.Diff 的比较逻辑4.简 ...

  4. vue+django 微博舆情系统源码、深度学习+舆情扩散消失分析、舆情紧急等级、属地分析、按话题、情感预测、话题评论获取、提取观点、正面负面舆情、按区域检测舆情

    项目背景 315又马上要到了,现在有开始对食品安全话题的关注地提升了,因此,本文系统对微博的食品安全话题进行分析,有如下的功能 1.展示当前食品安全事件相关的热点信息以及提供根据食品关键词,食品安全类 ...

  5. 通过自定义组件学习Vue系列(二)【时间轴】(附源码)

    需求: 用于升级日志的显示 效果图: 实现原理: 主要区域分为两块,时间区和内容区,时间区是画一个圆点和显示一个时间,内容区左边一个竖线和文字显示 然后做一下循环,将每个日期的数据显示出来 布局采用f ...

  6. vue函数如何调用其他函数?_从源码中学Vue(一)生命周期中的钩子函数的那点事儿...

    欢迎来到我的<从源码中学Vue>专题系列文章,更多精彩内容持续更新中,欢迎关注 :) Vue作为当下前端最流行的框架之一,在国内占绝对的优势.所以接下来我们一起来学习它吧! 我不会像其它人 ...

  7. 学习 vuex 源码整体架构,打造属于自己的状态管理库

    前言 这是学习源码整体架构第五篇.整体架构这词语好像有点大,姑且就算是源码整体结构吧,主要就是学习是代码整体结构,不深究其他不是主线的具体函数的实现.本篇文章学习的是实际仓库的代码. 其余四篇分别是: ...

  8. 小姐姐笔记:我是如何学习简单源码拓展视野的

    大家好,我是若川.这是我上周组织的源码共读纪年小姐姐的笔记,写得很好.所以分享给大家.欢迎加我微信 ruochuan12,进源码共读群.其他更多人的笔记可以阅读原文查看. 川哥的源码解读文章:据说 9 ...

  9. 学习 launch-editor 源码整体架构,探究 vue-devtools「在编辑器中打开组件」功能实现原理...

    1. 前言 你好,我是若川[1],微信搜索「若川视野」关注我,专注前端技术分享,一个愿景是帮助5年内前端开阔视野走向前列的公众号.欢迎加我微信ruochuan12,长期交流学习. 这是学习源码整体架构 ...

最新文章

  1. Spring Cloud入门教程 - Zuul实现API网关和请求过滤
  2. 计算机论文图,【论文】计算机图像学
  3. python开发上位机软件-UR机器人通信--上位机通信(python)
  4. “做实体店,已经是绝路了吗?”
  5. win7 系统激活工具 亲测可行
  6. iOS 手动实现KVO / iOS KVO底层原理
  7. 可视化 | Python时间序列化NBA球星赛季数据
  8. 用计算机打字用英语怎么说,打字用英语怎么说
  9. 毕业设计_Android短信查询及加密系统_短信查询
  10. 2021全球程序员收入报告出炉!字节高级码农年薪274万元排第5【文末送5本书】...
  11. 不选主元的矩阵三角分解法
  12. [前端框架]-VUE(下篇)
  13. Kotlin真的值得学习吗?
  14. html中缩放级别为1,更改浏览器缩放级别
  15. 编写第一个JSP文件
  16. python 如果文件夹不存在 创建文件夹
  17. Java岗大厂面试百日冲刺 - 日积月累,每日三题【Day5,java面向对象程序设计教程课后答案
  18. sourcetree提交报错 git -c diff.mnemonicprefix=false -c core.quotepath=false --no-optional-locks ······
  19. 功能对等四个原则_奈达功能对等理论四个方面(词汇对等、句法对等、篇章对等、文体对等)...
  20. python tkinter数据库通讯录_python连接Mysql数据库写的小电话本

热门文章

  1. 初中计算机基础知识教程考试,2017年职称计算机考试基础知识教程详解(三十一)...
  2. c 是泛型程序设计语言,c ++中的“泛型编程”是什么意思?
  3. mongodb的id的唯一性_mongodb中的objectid是collection中唯一,还是全db唯一,还是全宇宙唯一?...
  4. java string转jsonobject_超赞!终于有网友用Java实现了第三方qq账号登录
  5. mysql执行shell命令_关键Docker命令:使用Docker必须掌握的公认宝典
  6. UE4学习-第三人称游戏的AI巡逻
  7. 随机迷宫c语言实验报告,[原创]递归随机迷宫生成算法详解
  8. 三圆相交阴影部分面积_小学六年级图形面积的题很多家长都不会,一些初中生也未必会做...
  9. android触摸屏idc,Android触摸屏IDC
  10. api与密度转换公式_API重度和密度换算公式