相信组件开发现在已经成为前端开发的范式了,我们在做前端开发时,大部分是在写组件,那我们就更需要了解 vue里组件到底是怎么渲染的。
    vue里的一个最重要的概念就是组件化,我们可以用小型的/独立的/可复用的组件构建大型复杂应用。
    几乎任意类型的应用界面都可以抽象为一个组件树。
    vue3源码.png
    我们使用vite和pnpm搭建项目。
    那么,我们就从入口文件main.ts出发,探索组件渲染的过程吧!
    此处为应用程序初始化

    1. import { createApp } from "vue"
    2. import App from "./App.vue"
    3. const proxy = createApp(App).mount("#app")
    4. console.log(proxy)

    可以看到入口函数:createApp函数

    1. const createApp = ((...args) => {
    2. // 创建 app 对象
    3. const app = ensureRenderer().createApp(...args);
    4. const { mount } = app
    5. // 此处重写了 mount 函数
    6. app.mount = (containerOrSelector) => {}
    7. return app
    8. })

    可以看出 createApp此函数主要做了 2 件事情:创建 app 对象和重写了 app.mount方法。

    1. 创建 app 对象

    首先它调用了ensureRenderer函数,创建了一个渲染器

    1. // 渲染相关的一些配置,比如更新属性的方法,操作 DOM 的方法
    2. const rendererOptions = extend({ patchProp }, nodeOps);
    3. function ensureRenderer() {
    4. return (renderer ||
    5. (renderer = createRenderer(rendererOptions)));
    6. }
    7. function createRenderer(options) {
    8. return baseCreateRenderer(options);
    9. }
    10. function baseCreateRenderer(options, createHydrationFns) {
    11. const render = () => {}
    12. return {
    13. render,
    14. // createAppAPI 利用闭包和函数柯里化的技巧
    15. createApp: createAppAPI(render, hydrate)
    16. }
    17. }
    • 又调用了createRenderer,此处rendererOptions包括了俩大配置对象nodeOps和patchProp
    • 又调用了baseCreateRenderer,此函数返回了 createApp和render函数
    • 此处的createApp是createAppApi函数进行柯里化转化返回的
    • 我们再看createAppApi,在app对象上封装了一系列方法,包括mountusecomponentdirective等,供使用者直接使用
    1. app.mount重写

    思考一下,为什么要重写这个方法?
    因为Vuejs不仅仅是Web平台应用,它的目标是跨平台渲染。而createApp内部的app.mount实现了标准的可跨平台的渲染流程:

    1. mount(rootContainer, isHydrate, isSVG) {
    2. if (!isMounted) {
    3. // 创建组件 vnode
    4. const vnode = createVNode(rootComponent, rootProps);
    5. if (isHydrate && hydrate) {
    6. hydrate(vnode, rootContainer);
    7. }
    8. else {
    9. // 渲染 vnode
    10. render(vnode, rootContainer, isSVG);
    11. }
    12. app._container = rootContainer;
    13. }
    14. }

    注:此处的hydrate暂时可以忽略,是SSR渲染相关。
    …待完善

    核心渲染流程

    1. 执行 mount 流程

    首先执行render函数,进行 vnode创建和渲染。

    组件拆箱子的流程