vue源码解读

拿起之前没写完的文章(2019-11-26),继续尝试分析 Vue源码。

一级目录

flow

更新:我想在已经会 ts了,现在来看 flow,一脸慈爱。

作者也坦诚当初选flow,押错了宝哈哈,现在vue3改成ts了,在这里不做深入理解,还是当个学习的过程。

js的灵活有目共睹,现在向强类型语言靠拢已获得更好的体验。flow类型检查分两种:

  • 类型推断。根据上下文推断类型,根据推断检查类型
  • 类型注释。提前写好期待的类型注释,flow根据注释进行判断

类型推断

自动推断

1
2
3
4
function split(str){
return str.split('')
}
split(11)// 这里会报错,自动判断期待的是字符串而不是数字

类型注释

1
2
3
4
function add(x:number,y:number):number{
return x + y
}
add('1'+1) // 这样就能检查出错误
  • 数组 var arr:Array<number>=[1]
  • 对象 var obj:{a:string}:{a:'string'}

vue咋用的flow?

vue2.x 根目录Vue/flow 随便打开一个js:

细节不仔细看了,这样就搞定了一个顶级目录。

src

一图胜千言:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
src
├── compiler # 编译相关,
├── core # 核心代码
├──── components # 通用组件 keep-alive
├──── global-api # 全局api
├──── instance # 构造函数等 重点
├──── observer # 响应式相关
├──── util
├──── vdom # 虚拟DOM
├── platforms # 不同平台的支持
├──── web
├────── compiler
├────── runtime
├────── server
├────── util
├──── weex
├── server # 服务端渲染
├── sfc # .Vue 文件解析
├── shared # 共享代码

阅读源代码这里是重头戏,clone官方仓库,执行安装依赖:

1
2
3
npm i # 会下载e2e的依赖,可跳过,也可以无脑cnpm i
npm i -g rollup # rollup
# "dev": "rollup -w -c scripts/config.js --sourcemap --environment TARGET:web-full-dev"

dist

dist内有很多版本,我们用的是 runtime+esm ,用于webpack+预编译

demo阶段都是 vue.js UMD规范


el,template,render

el可以是 Element 也可以是 string,如果是string,dom查询得到

1
2
3
4
5
6
7
8
// 伪代码
if(!$option.render){ // render不存在
if($options.template){
// xxx
}else if(el){
// xxx
}
}

new Vue是如何启动的?这里我做了一个图:

Vue启动

执行挂载:

  • mountComponent 执行挂载,VDOM – DOM
  • new Watcher() 一个watchr
  • updateComponent 判断是否是第一次,第一次初始化,后续diff更新
  • update
  • render

new Vue() – _init() 内部 – $mount() – mountComponent() – updateComponnet()/new Watcher() – render() – _update()


数据响应式

关注 src/core/instance/state.jsinitState

组件里data是return,子组件不需要?

为了防止数据污染。根实例可以不考虑污染问题。

早前内容

源码构建

和构建有关的就三句,这三句展示传的参数不同。

进入 Vue/scripts/build.js

去看scripts/config.js 也是。按照 rollup的规则构建,参数分别是:

  • entry 入口 dest 出口
  • format 打包格式,打包成不同的 cjs es umd
  • env 环境变量 dev 和 prod

Runtime only 和 Runtime+Compiler
带不带编译器,渲染完的不需要再编译。

入口开始

观察这个src/platforms/web/entry-runtime-with-compiler.js

按图索骥,我们 import的vue,到底是怎么回事:

  • src/platforms/web/entry-runtime-with-compiler.js line7 import Vue from './runtime/index'
  • src/platforms/web/runtime/index.js line3 import Vue from 'core/index'
  • src/core/index.js
    • line1 import Vue from './instance/index'
    • line6 initGlobalAPI(Vue)
  • src/core/instance/index.js

这这里找到 Vue,用function实现的类。

1
2
3
4
5
6
7
8
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)
}

通过 new 来实例化。后面 initMixin(Vue) 都是把Vue传入,给Vue.prototype 扩展一些方法
Vue按照功能把这些拓展分散到各个模块中去实现,好维护。

initGlobalAPI 给Vue对象本身扩展全局的静态方法 src/core/global-api/index.js

这里后面跟进。

模板编译

这里我把文章独立出来了

vue模板编译原理

参考链接

这篇分析主要参考的这个网站,除了文字版还搭配了视频版。
https://ustbhuangyi.github.io/Vue-analysis/v2/prepare/directory.html

另一个偏,介绍 Vue-cli 源码的,还没开始看
https://kuangpf.com/Vue-cli-analysis/

请我喝杯咖啡吧~