Unraveling Vue 3 Initialization: From createApp to VNode Rendering

This article walks through Vue 3's initialization process, explaining what createApp(App).mount('#app') does, how the runtime‑dom and runtime‑core modules create and render VNodes, and how patch, shapeFlags, and patchFlags drive efficient DOM updates.

WeDoctor Frontend Technology
WeDoctor Frontend Technology
WeDoctor Frontend Technology
Unraveling Vue 3 Initialization: From createApp to VNode Rendering

Goal

Understand what createApp(App).mount("#app") actually does and explore Vue 3.0's initialization rendering process.

What You’ll Gain

Insight into Vue 3.0's initialization flow.

Direction for reading Vue 3.0 source code.

Getting Started

Clone the vue-next repository, enable source maps in package.json, and run yarn dev. This builds vue.global.js and its sourcemap, allowing step‑by‑step debugging of the call stack.

Runtime‑dom

The createApp() function originates from runtime-dom. It registers a mount method on the app instance, enabling a basic demo to run without errors.

const app = {data(){return {counter:1}}}
Vue.createApp(app).mount("#app")

Key functions include ensureRenderer (which obtains a renderer via createRenderer from runtime-core) and the platform‑specific nodeOps that wrap DOM APIs.

Runtime‑core

Inside runtime-core, baseCreateRenderer (≈2000 lines) builds the core rendering logic. createApp is created by createAppAPI, ultimately returning an app object with a mount method.

First Render: .mount("#app")

The demo uses the classic API. The dom‑mount implementation prepares the container, extracts the template if needed, clears the content, and calls the core mount function.

const { mount } = app;
app.mount = (containerOrSelector) => {
  const container = normalizeContainer(containerOrSelector);
  if (!container) return;
  const component = app._component;
  if (!isFunction(component) && !component.render && !component.template) {
    component.template = container.innerHTML;
  }
  container.innerHTML = "";
  const proxy = mount(container);
  container.removeAttribute("v-cloak");
  return proxy;
};

The core mount creates a root VNode, then calls render, which delegates to patch.

Creating the Root VNode

The VNode is initialized with properties such as type, shapeFlag, patchFlag, etc. shapeFlag uses bitwise enums (e.g., ELEMENT=1, STATEFUL_COMPONENT=4) to identify node kinds.

export const enum ShapeFlags {
  ELEMENT = 1,
  FUNCTIONAL_COMPONENT = 1 << 1,
  STATEFUL_COMPONENT = 1 << 2,
  TEXT_CHILDREN = 1 << 3,
  ARRAY_CHILDREN = 1 << 4,
  // ... other flags
}

Patch flags (e.g., TEXT=1, CLASS=1<<1) mark dynamic parts for optimized diffing.

export const enum PatchFlags {
  TEXT = 1,
  CLASS = 1 << 1,
  STYLE = 1 << 2,
  PROPS = 1 << 3,
  FULL_PROPS = 1 << 4,
  // ... other flags
}

Patch Process

patch

examines a VNode's type and shapeFlag to dispatch to specific processors (e.g., processElement, processComponent, processFragment, processText, etc.). It handles mounting when no previous VNode exists and updating otherwise.

if (n1 && !isSameVNodeType(n1, n2)) {
  // unmount old tree
  n1 = null;
}
const { type, shapeFlag } = n2;
switch (type) {
  case Text:
    processText(n1, n2, container, anchor);
    break;
  // ... other cases
  default:
    if (shapeFlag & ShapeFlags.ELEMENT) {
      processElement(...);
    } else if (shapeFlag & ShapeFlags.COMPONENT) {
      processComponent(...);
    }
}

Fragment, Teleport, and Suspense are new Vue 3 components, each identified by distinct shapeFlag values.

Component Mounting

During mounting, Vue creates a component internal instance, initializes props and slots, sets up reactivity, and compiles the template into a render function. The render function returns a VNode tree, which is then patched into the DOM.

function componentEffect() {
  if (!instance.isMounted) {
    const subTree = (instance.subTree = renderComponentRoot(instance));
    patch(null, subTree, container);
    instance.isMounted = true;
  } else {
    // update path
  }
}

Reactivity is driven by effect, which tracks dependencies during the render and triggers updates when reactive state changes.

Summary

The article dissects Vue 3’s bootstrapping: cloning the source, enabling source maps, tracing createApp through runtime-dom and runtime-core, understanding VNode creation, the role of shapeFlag and patchFlag, and how the patch algorithm efficiently mounts and updates the DOM.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

frontendRenderingRuntimeVue.jspatchVue3vnode
WeDoctor Frontend Technology
Written by

WeDoctor Frontend Technology

Official WeDoctor Group frontend public account, sharing original tech articles, events, job postings, and occasional daily updates from our tech team.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.