Appearance
前言
看了村长的源码共读,觉得还是要以自己的一种方式来记录自己的学习,不然今天学明天忘,纯属瞎扯淡。
村长说:为什么学习源码?一共总结了四个点:面向工资、内卷、加深理解与增强解决的问题的能力、学习大佬的编程思想。学习源码能够很好的修炼内功,形成一个很好的学习圆满方式和思维,以后再去学习其他的源码时,就会轻松很多啊。这就相当于提升自己的内功一起,实际上自身的学习能力也会快速提高。
村长学习方法: 第一种:首先要有一条主线,要沿着一条线看下去,看见一个知识点之后有引出另一个知识点,又跑到另一个知识点了,这样会让你容易银企一个问题,你会陷进去源码森林的迷宫里头,很容易迷路。
第二种:画思维导图,可以下次再打开的时候,按着顺序学习
第三种:提出一个问题,去源码中找到答案
第四种:造一个轮子,譬如:大崔哥的mini-vue
那我们这次的主线是什么呢?在写vue的时候,肯会有有一个createApp的过程
很显然,这次的主线就是先看看这个createApp是如何创建的
环境搭建
js
git clone git@github.com:vuejs/core.git
git clone git@github.com:vuejs/core.git
因为vue3的管理包已经更换了使用了pnpm
js
npm i -g pnpm
npm i -g pnpm
克隆下来的项目,首先要查看package.json
将这个大包删掉,不然下载依赖的时候会比较慢
修改运行命令,添加 --sourcemap
执行启动命令,跟下图一样则说明成功了:
初始化流程分析
那接下来我们就可以测试了,怎么测试 刚才这个打包就可以调试呢,可以在这个路径下打开这个案例packages\vue\examples\composition\todomvc.html
在浏览器中打开这个案例,打开控制台,按Ctrl+P
输入刚才打开的文件的名字寻找。
可以设置一个断点在这里,刷新页面:
当我们点击继续执行的时候,会发现会跳转到了一个新的文件,路径为:packages\runtime-dom\src\index.ts
,可以看出creatApp是从这里来的
在源码中可以看出,上面这个方法是返回了一个app。
这个是执行mount
这个时候我们又要去看一下ensureRenderer
这个函数了得到一个渲染器renderer
-creatApp
。在vscode中可以直接按住Ctrl键,鼠标点击,就可以直接跳转了。
跳转发现又去执行了
createRenderer
,再跳转,这是后发现路径文件变为了:packages\runtime-core\src\renderer.ts
上图可以看出在去执行了baseCreateRenderer
,这个时候跳转,你会发现它是个TS函数重载的,vue3最大的函数。
整体的内容2000多行代码就很多。
会发现
baseCreateRenderer
返回的是一个对象,对象里面有三个内容。render:
就是我我们所说的渲染函数,通过patch虚拟DOM和diff算法最后渲染上树的一个过程。hydrate:
是SSR渲染的。这次我们主要看的是createApp
,它是createAppAPI
的返回,再跳转路径为:packages\runtime-core\src\apiCreateApp.ts
通过creatApp里面的对象内容传进来的,会被理解成为一个根组件,vue2是接受到的组件的配置对象,vue3直接理解为根组件配置对象或者组件实例,调用组件实例的render(),得到vnode通过patch的diff算法,再转化成DOM树
这个就是App实例,app-mount
创建根组件的虚拟DOM,只执行一次,通过传进来的render
函数,渲染vnode到dom追加到根元素rootContainer上
这时候要回到packages\runtime-core\src\renderer.ts
的baseCreateRenderer
,查看render
函数的来源,首次渲染,首次执行根组件的vndoe 作为patch函数参数二,参数一是null,会执行挂载
很显然我们执行的
else
里面的patch
,跳转到patch函数,初始化执行的是patch中这段:
再跳转processComponent
需要再跳转mountComponent
,首次挂载根组件,以后还会执行因为还会有其他子组件了。
组价挂载过程: 1、组件实例 2、初始化组件实例、插槽、数据等。setupComponent
3、获取vnode。setupRenderEffect
这里方法中有个初始化组件的方法setupComponent
再跳setupComponent
。这个时候路径已经发现了改变了:packages\runtime-core\src\component.ts
再跳setupStatefulComponent
,初始化setup添加响应式
会再执行finishComponentSetup
这里就可以解释为什么有些组件没有render函数但是也会渲染出来的原因了
在mountComponent
中还会执行另外一个方法setupRenderEffect
1、创建一个组件的更新函数 componentUpdateFn
1-1、render获取Vnode
1-2、patch(oldVnode,vnode)
2、创建更新机制 new ReactiveEffect(更新函数)
3、首次执行update
将将vnode转为DOM
提出问题:渲染器是什么,作用是什么?
渲染器是个对象,一个是renderer的方法:react中有个React.render(,"#app")是一样的功能,它把接收到的虚拟DOM转换成DOM对象,追加到宿主元素上去。一个是hydrate的方法,服务端SSR渲染,将一个虚拟DOM直接生成HTML字符串。一个creatApp的方法:创建app实例,是通过ceartAppApi这个工厂函数返回的
作用:首次渲染、获取应用程序的实例
提出问题:挂载做了什么事情?
只执行一次、初始化看到第一次渲染结果、建立更新机制(不停循环)
提出问题:组件不一定有渲染函数,但是一定会渲染出来,这是为什么呢?
这就是编译器,因为那个编译器其实可以把当前这个组件所挂载的那个目标里面的内容,给它当成一段HTML代码把它编译成渲染函数
总结
手动记录一下,方便下次学习