--- title: Vue3架构原理 date: 2025-12-15 23:25 --- # 一、Vue3 整体架构图 ```mermaid graph TD A[Vue 3] --> B[Compiler] A --> C[Runtime] A --> D[Reactivity] B --> B1[Parser] B --> B2[Transformer] B --> B3[Codegen] C --> C1[Virtual DOM] C --> C2[Renderer] C --> C3[Component] D --> D1[Proxy] D --> D2[Effect] D --> D3[Dependency Graph] B3 -->|生成| C1 C1 -->|Diff/Patch| C2 D3 -->|驱动更新| C1 ``` ## 1.1 编译器模块   编译器负责将模板转换为可执行的渲染函数,包含**解析器(Parser)、转换器(Transformer)和代码生成器(Codegen)** 三个子模块。 - compiler-core: 核心编译器,负责基础的编译功能,如生成抽象语法树(AST)、基础的模板编译等,是平台无关的编译器核心。 - compiler-dom: 基于compiler-core,针对浏览器环境的编译模块,重写了编译和解析方法,处理与原生 DOM API 相关的编译工作。 - compiler-sfc: 用于处理 Vue 单文件组件(.vue)的编译,将单文件组件中的模板、脚本和样式进行解析和编译。 - compiler-ssr:服务端渲染的编译模块,负责在服务端将 Vue 组件编译为适合服务器端渲染的代码。 ## 1.2 运行时模块   运行时系统处理**虚拟DOM的创建、更新和渲染**,包含组件实例管理、虚拟DOM diff算法和平台渲染器。 - runtime-core:运行时核心模块,包含了 Vue 组件的生命周期、虚拟节点(vnode)、观察者(watch)等核心 API,是平台无关的运行时核心。 - runtime-dom:运行时与 DOM 相关的核心模块,提供了与浏览器 DOM 交互的功能,如创建应用实例、操作 DOM 元素等。 ## 1.3 响应式系统   响应式系统基于Proxy实现数据劫持,通过依赖收集和触发更新机制驱动视图变化。   三大系统协同工作:编译器生成的渲染函数由运行时执行,响应式系统追踪数据变化触发组件更新,形成完整的渲染闭环。 # 二、基础模块 ## 2.1 响应式系统 ```mermaid graph LR classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px A(原始对象):::process -->|Proxy 包装| B(响应式对象):::process B -->|属性读取| C(依赖收集):::process B -->|属性修改| D(触发更新):::process C --> E(副作用函数):::process D --> E E -->|更新视图| F(真实 DOM):::process ```   Vue3的响应式系统通过Proxy代理对象属性,在get操作时通过track函数收集当前正在执行的副作用(如组件渲染函数)作为依赖,存储到依赖关系图中。当set操作发生时,trigger函数根据依赖关系图找到所有关联的副作用函数,通过调度器批量执行。   这种设计使得数据变化能精准触发组件更新,同时通过异步批处理避免重复渲染。   响应式系统独立于其他模块,可单独使用,为Vue3提供了高效的状态管理能力。 ## 2.2 虚拟 DOM ```mermaid graph LR classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px A(旧虚拟 DOM 树):::process -->|Diff 算法| B(差异比较):::process C(新虚拟 DOM 树):::process --> B B -->|更新操作| D(真实 DOM):::process ```   当组件更新时,Vue会比较新旧虚拟DOM树的差异。通过Patch Flags快速识别动态节点类型(如文本、样式等),仅对标记为动态的部分进行比较;对于带key的子节点列表,使用最长递增子序列算法最小化DOM操作;完全静态的子树则直接跳过diff过程。   这种靶向更新策略将传统虚拟DOM算法O(n³)的时间复杂度优化到接近O(n),同时配合异步批量更新机制,确保复杂应用也能保持流畅渲染 ## 2.3 编译器 ```mermaid graph LR classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px A(模板字符串):::process -->|解析| B(抽象语法树 - AST):::process B -->|转换| C(优化后的 AST):::process C -->|生成| D(渲染函数代码):::process ```   Vue编译器将模板字符串转换为渲染函数,经历解析、转换和代码生成三个阶段。   解析阶段通过词法分析生成原始AST抽象语法树;转换阶段对AST进行优化,包括静态节点提升(将不变节点提取到渲染函数外部)、补丁标记(给动态节点添加优化标识)、树结构打平(减少动态子节点的嵌套层级);最后代码生成阶段输出优化的渲染函数。   这些优化使得运行时能跳过静态内容比较,直接定位动态节点,大幅提升渲染性能。 ## 2.4 渲染器 ```mermaid graph LR classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px A(虚拟 DOM 树):::process -->|创建节点| B(真实 DOM 节点):::process B -->|插入节点| C(页面):::process A -->|更新节点| B ```   Vue渲染器是连接虚拟DOM与真实平台的桥梁,分为虚拟DOM处理层、Patch算法层和平台操作层。   它通过抽象平台API(如createElement、insert等)实现跨平台能力,开发者可配置不同平台的底层操作来支持Web、Canvas甚至原生应用。   渲染器内部采用增量更新策略,结合编译器提供的优化提示(如静态标记、动态子节点索引),确保DOM操作最精简。   这种设计使Vue在保证Web端高性能的同时,也能灵活适配各种渲染环境。 # 三、Vue3应用生命周期 ## 3.1 初始化阶段   流程: 1. 调用`createApp()`创建应用实例 2. 创建平台专属渲染器(DOM/SSR/Test) 3. 初始化应用上下文和插件系统   关键代码: ```typescript // runtime-dom/index.ts const renderer = createRenderer({ patchProp, // DOM属性操作 ...nodeOps // DOM节点操作集合 }) function createApp(rootComponent) { const context = createAppContext() const app = { _component: rootComponent, mount(container) { const vnode = createVNode(rootComponent) renderer.render(vnode, container) return vnode.component.proxy } } return app } ``` ## 3.2 组件挂载阶段   流程: 1. 标准化容器(字符串选择器 → DOM元素) 2. 创建根组件虚拟节点(vnode) 3. 初始化组件:解析props和slots、执行setup函数、建立响应式连接等 4. 建立渲染effect,为组件创建响应式的副作用函数   关键代码: ```typescript // runtime-core/renderer.ts function mountComponent(vnode, container) { // 1. 创建组件实例 const instance = createComponentInstance(vnode) // 2. 初始化组件 setupComponent(instance) // 3. 建立渲染effect setupRenderEffect(instance, container) } function setupRenderEffect(instance, container) { instance.update = effect(() => { if (!instance.isMounted) { // 首次渲染 const subTree = (instance.subTree = renderComponentRoot(instance)) patch(null, subTree, container) instance.isMounted = true } else { // 更新渲染 const nextTree = renderComponentRoot(instance) patch(instance.subTree, nextTree, container) instance.subTree = nextTree } }, { scheduler: queueJob }) } ``` ## 3.3 响应式更新阶段   流程: 1. 数据变更触发Proxy的set拦截 2. 通过trigger触发依赖的effect 3. 调度器将更新任务加入队列 4. 下一个tick执行队列中的任务 5. 执行组件render函数生成新vnode 6. 调用patch进行差异更新   关键代码: ```typescript // reactivity/reactive.ts function createReactiveObject(target) { return new Proxy(target, { set(target, key, value, receiver) { const oldValue = target[key] const result = Reflect.set(target, key, value, receiver) if (hasChanged(value, oldValue)) { trigger(target, key) // 触发更新 } return result } }) } // runtime-core/scheduler.ts const queue = [] function queueJob(job) { if (!queue.includes(job)) { queue.push(job) queueFlush() } } function queueFlush() { if (!isFlushing) { nextTick(flushJobs) } } function flushJobs() { isFlushing = true queue.sort((a, b) => a.id - b.id) // 保证父组件先更新 for (let i = 0; i < queue.length; i++) { queue[i]() } queue.length = 0 isFlushing = false } ``` ## 3.4 虚拟DOM Patch阶段   流程: 1. 比较新旧vnode的类型 2. 不同类型:卸载旧节点,挂载新节点 3. 相同类型:更新节点 4. 子节点对比采用高效diff算法   关键代码: ```typescript // runtime-core/renderer.ts function patch(n1, n2, container) { // 1. 类型不同直接卸载 if (n1 && !isSameVNodeType(n1, n2)) { unmount(n1) n1 = null } const { type, patchFlag } = n2 // 2. 根据类型处理 switch (type) { case Text: processText(n1, n2, container) break case Fragment: processFragment(n1, n2, container) break default: if (shapeFlag & ShapeFlags.ELEMENT) { processElement(n1, n2, container) } else if (shapeFlag & ShapeFlags.COMPONENT) { processComponent(n1, n2, container) } } } function processElement(n1, n2, container) { if (n1 == null) { mountElement(n2, container) } else { patchElement(n1, n2) } } function patchElement(n1, n2) { // 根据patchFlag进行优化更新 if (n2.patchFlag & PatchFlags.FULL_PROPS) { // 全量props更新 } else { // 只更新动态props } // 更新子节点 patchChildren(n1, n2) } ``` ## 3.5 组件卸载阶段   流程: 1. 触发beforeUnmount生命周期钩子 2. 停止组件渲染effect 3. 递归卸载子组件 4. 移除DOM节点 5. 触发unmounted生命周期钩子 6. 清理响应式依赖   关键代码: ```typescript // runtime-core/renderer.ts function unmount(vnode) { if (vnode.type === Fragment) { unmountChildren(vnode.children) return } const { component } = vnode if (component) { unmountComponent(component) } else { remove(vnode.el!) } } function unmountComponent(instance) { // 1. 触发beforeUnmount if (instance.bum) { invokeArrayFns(instance.bum) } // 2. 停止响应式effect stop(instance.update) // 3. 递归卸载子树 unmount(instance.subTree) // 4. 触发unmounted if (instance.um) { queuePostRenderEffect(instance.um) } // 5. 清理引用 instance.isUnmounted = true } ``` ## 3.6 编译阶段   流程: 1. 将模板解析为AST 2. 转换AST(静态提升/标记PatchFlag) 3. 生成可执行的渲染函数代码 4. 运行时直接使用优化后的渲染函数   关键代码: ```typescript // compiler-core/src/compile.ts function baseCompile(template, options) { // 1. 解析阶段 const ast = parse(template) // 2. 转换阶段 transform(ast, { hoistStatic: true, // 静态提升 nodeTransforms: [ transformIf, transformFor, transformExpression ] }) // 3. 代码生成 const code = generate(ast, { mode: 'function', runtimeGlobalName: 'Vue', prefixIdentifiers: true }) return { ast, code: `with(this){return ${code}}` // 生成渲染函数 } } ```