0
点赞
收藏
分享

微信扫一扫

【Vue3源码共读】第二期:源码层面探索Vue3初始化

作者:小杨哥


回顾


各位亲爱的小伙伴,第二期的Vue3.0源码共读来啦!!!
本期内容小编将给大家带来:

  • 分析启动脚本
  • 查找入口文件
  • 看看首次编译过程,从源码层面解析初始化细节

在我们开始这期内容之前,小编先带领大家回顾一下上期的知识点。

【Vue3源码共读】第二期:源码层面探索Vue3初始化_依赖关系

还是从这张图开始,在上期内容中我们谈到,Vue3.0的源码中最为核心的包就是叫做以 vue 命名的文件包,在这个包内有三个依赖关系,其中 runtime-domcompiler-dom 是明显的依赖关系,但其中还有一个隐性的依赖叫做 reactivity 的依赖,这里面主要是做响应式的一些处理,后期小编会带领大家着重探讨这个依赖包的原理,而其实真正的依赖在 runtime-core 这个包里,这个包才是真正告诉你 createApp 是怎么由来的,内部又做了哪些事情。

【Vue3源码共读】第二期:源码层面探索Vue3初始化_d3_02

小编这里梳理了一下逻辑关系图,createApp 这个方法最终在 createAppAPI 内部有一个工厂函数在这里得到了一次扩展 createApp 的方法,扩展此方法最为重要的一点就是为了让这个函数变得更加通用,我们知道在 createApp 里面传入一个 render 函数,但是对于 createApp 来说它只管调用传入进来的参数,而并不关心你这个参数做了哪些的逻辑处理,真正我们能够使用实例上的方法就是来源这个 createAPI 扩展之后得到的属性,例如 component mixin use

正文

经过之前的内容回顾,想必大家对 createApp 已经有了深刻的了解,接下来将进入到本章内容的核心部分,首先带领大家分析启动脚本,看看启动脚本都做了哪些事情。

"dev": "node scripts/dev.js --sourcemap",

这行代码想必大家应该都不陌生吧,这就是我们启动项目的运行脚本我们就要从 dev.js 这个脚本文件开始下手。

【Vue3源码共读】第二期:源码层面探索Vue3初始化_初始化_03

WeChat46b3d93f7c154ae5e1b95022c46eb57b.png

minimist 是专门用来解析传进来的参数,什么意思呢?当我们在运行 npm run dev 这行命令的时候实际上是运行 node scripts/dev.js 当后面的路径传入 -- 或者 - 的时候会被解析成为第一个参数,否则会打包成 vue 的包。

【Vue3源码共读】第二期:源码层面探索Vue3初始化_d3_04

WeChat96a3eefa625cef34b030b68fe2353724.png

在这张图中也能看出 dev-sfc 部分使用的打包格式为 esModule 格式,在浏览器中则会以 type=module 出现。那么我么现在知道指令映射的代码中的含义了,那么问题来了下一步我们该干什么呢?哈哈哈~ 如果对工程化的框架比较了解的话,我们就要看看打包工具的配置文件,看看打包过后你的 entry 入口文件和你的 export 打包后输出文件是怎样配置的,在源码中使用的是 rollup 打包生成的,所以我们要浏览一下 rollup.config.js 这个配置文件。

【Vue3源码共读】第二期:源码层面探索Vue3初始化_d3_05

WeChatc8eb0ccf03ff5fb6b79d0ed338c01de1.png

在配置系文件中我们就可以看到,所有获取包目录都是从 packages 中得来的,通过 process.env.TARGET 进行包名的路径拼接,就会得到 /packages/xxx

【Vue3源码共读】第二期:源码层面探索Vue3初始化_d3_06

WeChat024e26087aec3918dc0ecf425d3c7580.png

这里就是要配置的一些打包选项,例如 CommonJs ECMAScript 格式,这里讲一下 iife 格式,就是打包后生成一个匿名函数自调的格式,(()=>{})()

【Vue3源码共读】第二期:源码层面探索Vue3初始化_d3_07

WeChat465926fb4d72cd8107ca6bf763ffba32.png

这里我们看到真正打包的是以 runtime 开头的包名称,这时候他会根据你的指令中是否包含 -f runtime-xxx 这种格式的映射,生成两种第一个是运行时打包,没有在初始化的时候把编译器打包进去,第二个则是全量打包。

【Vue3源码共读】第二期:源码层面探索Vue3初始化_初始化_08

WeChatee256bb4095f1e2a86c2e2321b505971.png

所以,我们就找到了在 packages/vue/index.ts 这个路径下的包,在这个包里面有一个叫做 compileToFunction 编译函数其真正的作用就是一个是解析 template 中的 innerHhtml,另一个就是生成一个 render 渲染函数,另外,在这个函数中他会判断你传进来的参数是不是以字符串形式的模板另外一个是不是 dom,就是说支持的写法 mount("< div>xxx</ div>")  mount('#app') 或者 mount(app)

【Vue3源码共读】第二期:源码层面探索Vue3初始化_初始化_09WeChat98c822fa89560f875415a68ff6276a83.png

这里在 callStack 中就真正的解析了 compileToFunction 是如何一步一步的变成渲染函数。

【Vue3源码共读】第二期:源码层面探索Vue3初始化_依赖关系_10

WeChat00a9bbcb59649cbbf8b1ce99b6c81d43.png【Vue3源码共读】第二期:源码层面探索Vue3初始化_d3_11

WechatIMG81.jpeg

从这个上面我们就看出,template 真正就是传入的 innterHtml

【Vue3源码共读】第二期:源码层面探索Vue3初始化_依赖关系_12

WeChat70bfdad15d56582ac1f31f3ea6ccab68.png

通过浏览器调试后我们就得出 compileToFunction 是在 finishComponentSetup 这个函数中调用的,而 template 就是要解析的 innerHTML

【Vue3源码共读】第二期:源码层面探索Vue3初始化_初始化_13

WeChat5f3653a52a450b5ece0d35a757cabe17.png

vue包中使用 registerRuntimeCompiler 将 compileToFunction 这个函数注册,这是为了初始化需要编译时能够调用它。这里原封不动导出 runtime-dom,因此有了vue -> runtime-dom -> runtime-core这样的依赖关系。

【Vue3源码共读】第二期:源码层面探索Vue3初始化_d3_14

WeChat581967ab4ceb37c6fefa2ed599d85bad.png【Vue3源码共读】第二期:源码层面探索Vue3初始化_依赖关系_15

WeChat802ba115543725ce52877e96d64aa870.png

随后的流程就是:

createRenderer() => baseCreateRenderer() =>
createAppAPI(render, hydrate) => createApp()

app.mount() => render() => patch(n1, n2)  =>
processComponent() => mountComponent() 

这里我们主要研究一下 mountComponent() 挂载组件做了哪些事情。

【Vue3源码共读】第二期:源码层面探索Vue3初始化_依赖关系_16

WechatIMG82.jpeg

【Vue3源码共读】第二期:源码层面探索Vue3初始化_依赖关系_17

WeChat280ea252a066a6ad52f94d5f261b9ba3.png

在这个函数内主要有两个函数调用,一个是 createComponentInstance 创建组件实例,另一个是 setupComponent 初始化组件实例,从这个函数开始找寻。

【Vue3源码共读】第二期:源码层面探索Vue3初始化_初始化_18WechatIMG86.jpeg【Vue3源码共读】第二期:源码层面探索Vue3初始化_初始化_19WechatIMG87.jpeg

在这里我们就看到组件初始化接收的就是一个 setup 这块对传入不同方法做了各种处理,例如 promise随后会在 handleSetupResult() 这个方法内处理 setup 的返回值。

【Vue3源码共读】第二期:源码层面探索Vue3初始化_依赖关系_20

WechatIMG88.jpeg

根据 setup 返回不同的类型作出处理,比如 返回的是一个函数,对象或者字符串之类的。

【Vue3源码共读】第二期:源码层面探索Vue3初始化_依赖关系_21

WechatIMG89.jpeg

执行完毕后都会走 finishComponentSetup() 这个方法。

【Vue3源码共读】第二期:源码层面探索Vue3初始化_初始化_22

WeChatde62b32d0810ec4d669cb295a41fd91a.png【Vue3源码共读】第二期:源码层面探索Vue3初始化_d3_23

WeChat3cc852f1a9e27e9a71503075b277a1c8.png

所以在这个函数内真正的是 返回一个 render 函数,并且兼容 Vue2.0 的方法。

到这里,基本上初始化所有的逻辑就理顺啦~

总结

这期内容小编就告诉大家从代码的层面一步步的深入了解初始化过程,首先是从 package.json 目录文件中锁定执行的哪个脚本文件,我们通常使用的打包工具如:webpack vite 或者 rollup 之类的都会有一个配置文件 xxx.config.js 从这个文件中我们就能锁定 entry 的入口文件,通过确定入口文件之后我们就能找到各个包之间的依赖关系,根据依赖包,一步步深挖理解初始化的整体流程。

顺便说一句 Vue3.0 在2022年2月7日将正式成为默认版本,届时我们安装的 vue 将会是3.x这个版本,属于Vue3的时代将正式开启!大家还在犹豫什么哪,赶紧跟村长一起学起来吧!


如果觉得文章对您有帮助,请“点赞”


举报

相关推荐

0 条评论