Vue 3 Source Code Analysis

website·Indexed 30 days ago

https://maxlz1.github.io/blog/

A technical deep dive into the internal implementation of Vue 3, covering the reactivity system (reactive, ref, computed, watch), the compiler's AST parsing process, the renderer's Virtual DOM and Diff algorithm, and component lifecycle management. Also includes source code analysis for Vue Router and Pinia.

Tokens
69K
Snippets
261
Records
363
Agent score
74%

What's inside Vue 3 Analysis

  1. Overview of Vue 3 component props initialization

    The initialization of component props in Vue 3 occurs in three primary stages:

    1. Normalization: Standardizing the props declared within the component and its inherited mixins/extends.
    2. Assignment: Determining which passed attributes are actual props and which are attrs, then setting the instance's props property.
    3. Validation: Verifying the passed props against the declared types (primarily in development mode).
  2. Overview of the Vue 3 Renderer and baseCreateRenderer

    The Vue 3 renderer converts Virtual DOM into real DOM (or other platform targets). The baseCreateRenderer function is used to create a renderer object containing three primary methods:

    • render: Used for client-side rendering.
    • hydrate: Used for isomorphic/server-side hydration.
    • createApp: Used to create the app instance.

    baseCreateRenderer encapsulates the core logic for mounting and updating components.

  3. Overview of the Vue 3 Diff Algorithm

    The Diff algorithm in Vue 3 is used during the update process to identify differences between a new virtual DOM (vnode) and an old vnode. Instead of a naive recursive traversal of the entire tree, Vue 3 uses a specialized patch process to target specific node types and a patchChildren mechanism to efficiently update lists of child elements.
  4. Overview of the vue-router Matcher

    The routerMatcher is a core internal component of vue-router responsible for managing route records and performing path matching. It is created via the createRouterMatcher function, which takes the route table (routes) and global options. The resulting matcher object provides an API for managing the routing state and resolving paths.
    export function createRouterMatcher(
      routes: RouteRecordRaw[],
      globalOptions: PathParserOptions
    ): RouterMatcher {
      // ...
      return { addRoute, resolve, removeRoute, getRoutes, getRecordMatcher }
    }
  5. Understand the Vue 3 Scheduler architecture

    The scheduler in Vue 3 manages the execution order of tasks (jobs) to ensure that APIs, lifecycle hooks, and component rendering happen in the correct sequence. It utilizes three primary queues to categorize tasks:

    1. pendingPreFlushCbs: Tasks to be executed before component updates (e.g., watchEffect).
    2. queue: The main component update task queue.
    3. pendingPostFlushCbs: Tasks to be executed after component updates (e.g., watchPostEffect).
  6. Understand how Vue 3 triggers component updates

    Vue 3 components are updated through a ReactiveEffect instance created during the mounting process. The componentUpdateFn serves as the effect's side-effect function. When the component's render function is executed within componentUpdateFn, it triggers the get and has interceptors of the reactive data used in the template, collecting these dependencies. When a reactive dependency is modified (triggering a set interceptor), the ReactiveEffect is triggered, which invokes the update scheduler job to run componentUpdateFn again, initiating the update process.
    const setupRenderEffect: SetupRenderEffectFn = (
      instance, 
      initialVNode, 
      container, 
      anchor, 
      parentSuspense, 
      isSVG, 
      optimized
    ) => {
      const componentUpdateFn = () => {
        // Renders the component root and updates instance.subTree
        const subTree = (instance.subTree = renderComponentRoot(instance))
      }
    
      // Create ReactiveEffect to track dependencies and trigger updates
      const effect = (instance.effect = new ReactiveEffect(
        componentUpdateFn,
        () => queueJob(update), // Scheduler job
        instance.scope
      ))
    
      const update: SchedulerJob = (instance.update = () => effect.run())
      
      update()
    }
  7. Understand Vue 3 component `this` resolution and property priority

    In Vue 3, this within a component points to instance.proxy, which is a proxy wrapper around instance.ctx. When accessing properties via this, Vue uses interceptors to resolve the value. To optimize performance, the source of a property (where it was found) is stored in instance.accessCache after the first lookup, allowing subsequent accesses to bypass the resolution logic and retrieve the value directly from the source object.

    When the same property name exists in multiple locations, Vue resolves them based on the following priority order (highest to lowest):

    1. setup
    2. data
    3. props
    4. computed
  8. Understand the role of the Vue 3 Renderer

    The primary task of the Vue 3 renderer is to convert Virtual DOM (VNode) into real DOM objects or other platform-specific representations (e.g., Canvas). This architecture allows Vue 3 to provide cross-platform capabilities by swapping the renderer implementation while keeping the core reactivity and component logic the same.
  9. Understand the Vue 3 VNode structure

    A Virtual DOM node (vnode) is a JavaScript object that describes a real DOM structure. It consists of a tree of nodes where each node defines the element type, its properties, and its children. In Vue 3, the VNode interface includes critical properties for rendering and optimization, such as shapeFlag (to identify node type) and patchFlag (to optimize the diffing process).
    {
      type: 'div',
      props: {
        id: 'container'
      },
      children: [
        {
          type: 'span',
          props: {
            class: 'span1'
          },
          children: 'Hello '
        },
        {
          type: 'span',
          props: {
            class: 'span2'
          },
          children: 'World'
        },
      ]
    }
  10. Understand in-component navigation guards in Vue Router

    In-component navigation guards are hooks that can be defined within a component to control navigation. In the Composition API, these are provided as onBeforeRouteLeave and onBeforeRouteUpdate. These guards are automatically removed when the component is unmounted. To function correctly, they must be called at the top of the setup function and must be used within a component that is a child of <router-view>.
  11. Understand Vue 3 Component Options Merging Logic

    Vue 3 uses the resolveMergedOptions function to merge a component's options. The merging priority follows this order (from lowest to highest priority, where higher priority overrides lower):

    1. Global Mixins
    2. extends options
    3. Local Mixins
    4. The component's own options

    To optimize performance, the resulting merged options object is cached in instance.appContext.optionCache. If no global mixins, local mixins, or extends are present, the base component options are used directly.

  12. Concept of Reactive Data in Vue 3

    Reactive data is data that can automatically trigger updates to dependent computations or side effects when its value changes. In standard JavaScript, updating an object property does not automatically re-run functions that used that property; reactive data solves this by enabling synchronization without requiring the developer to manually call the dependent functions again.
    // Non-reactive behavior:
    let obj = { a: 1, b: 1 }
    function sum(a: number, b: number) {
      return a + b
    }
    
    let c = sum(obj.a, obj.b) // c = 2
    obj.a = 2                 // c remains 2; sum() must be called again manually