← Back to all projects

VUEJS INTERNALS REACTIVITY MASTERY

In 2014, Evan You created Vue to combine the declarative nature of Angular with the lightweight flexibility of a library. When Vue 3 was released in 2020, it underwent a total internal rewrite. The shift from `Object.defineProperty` to `Proxy` wasn't just a syntax change; it was a fundamental shift in how reactivity is achieved in the browser.

Learn Vue.js Internals: From Proxy to Virtual DOM Master

Goal: Deeply understand the internal machinery of Vue.js 3—specifically the Reactivity API, Virtual DOM, and Template Compiler. You will learn how JavaScript Proxies enable transparent dependency tracking, how the Virtual DOM minimizes expensive browser updates, and how the compiler optimizes code before it even runs. By the end, you’ll have built a fully functional “Mini-Vue” from scratch, giving you the architectural insight to optimize any frontend application.


Why Vue.js Internals Matter

In 2014, Evan You created Vue to combine the declarative nature of Angular with the lightweight flexibility of a library. When Vue 3 was released in 2020, it underwent a total internal rewrite. The shift from Object.defineProperty to Proxy wasn’t just a syntax change; it was a fundamental shift in how “reactivity” is achieved in the browser.

Understanding these internals is the difference between a developer who uses Vue and an engineer who masters the web platform. It unlocks:

  • Zero-Guess Performance: You’ll know exactly why a component re-renders and how to stop it.
  • Framework Agnosticism: The principles of Proxies, VDOM diffing, and AST transformation apply to React, Solid, Svelte, and whatever comes next.
  • Architectural Clarity: You’ll understand why “Signals” are taking over the industry and how Vue was ahead of the curve.

Core Concept Analysis

1. The Reactivity Engine (The Heart)

Reactivity is the ability of a system to detect data changes and automatically run side effects. Vue 3 uses a “Pull-based” reactivity system with “Lazy Evaluation.”

DATA (Proxy) <---> DEP (Dependency Map) <---> EFFECT (The Worker)

ASCII: The Proxy Trap

   User Code: state.count++
          │
          ▼
┌─────────────────────────────────┐
│         Javascript PROXY        │
│  ┌───────────────────────────┐  │
│  │ trap: set(target, key)    │  │
│  └─────────────┬─────────────┘  │
└────────────────┼────────────────┘
                 │
                 ▼
┌─────────────────────────────────┐
│        TRIGGER FUNCTION         │
│  "Hey, state.count changed!"    │
│  Find all effects in the Map    │
└────────────────┬────────────────┘
                 │
                 ▼
┌─────────────────────────────────┐
│        RUN EFFECTS              │
│  1. Re-render UI                │
│  2. Update Computed             │
│  3. Run Watchers                │
└─────────────────────────────────┘

2. The Virtual DOM (The Strategy)

Changing the DOM is slow. Changing JavaScript objects is fast. The VDOM is a “blueprint” of what the UI should look like.

ASCII: The Patching Process

      Old VNode Tree               New VNode Tree
   ┌────── div ──────┐          ┌────── div ──────┐
   │ id: "app"       │          │ id: "app"       │
   └───────┬─────────┘          └───────┬─────────┘
           │                            │
   ┌────── h1 ───────┐          ┌────── h1 ───────┐
   │ text: "Hello"   │  DIFF -> │ text: "Vue 3"   │  <-- Change detected!
   └─────────────────┘          └─────────────────┘

          RESULT: Only one DOM operation: el.textContent = "Vue 3"

3. The Compiler (The Optimizer)

The compiler’s job is to be smarter than the developer. It analyzes your template and marks static vs. dynamic parts so the VDOM diffing algorithm can skip the static parts entirely.


Concept Summary Table

Concept Cluster What You Need to Internalize
The Proxy Trap How get and set traps capture dependencies and notify subscribers.
The Effect Stack How Vue keeps track of which function is currently running to “link” it to data.
VNode Lifecycle From creation (h function) to mounting and eventual patching.
Diffing Heuristics Why “Keys” matter and how Vue optimizes list reconciliation.
Static Hoisting How the compiler moves static code out of the render loop to save memory.

Deep Dive Reading by Concept

Reactivity & Proxies

Concept Book & Chapter
Proxies & Reflect “Eloquent JavaScript” by Marijn Haverbeke — Ch. 20: “Node.js” (Metaprogramming section)
Reactivity Design “Vue.js 3 Design and Implementation” by Huo Chunyang — Ch. 4: “The Design of Reactivity Systems”
Ref vs Reactive “Vue.js 3 Design and Implementation” by Huo Chunyang — Ch. 6: “The Concept of Ref”

Virtual DOM & Rendering

Concept Book & Chapter
VNode Structure “Vue.js 3 Design and Implementation” by Huo Chunyang — Ch. 7: “The Concept of Renderer”
Diffing Algorithms “Algorithms” by Sedgewick — Ch. 5: “Strings” (for sequence alignment concepts)
Component Mounting “Vue.js 3 Design and Implementation” by Huo Chunyang — Ch. 12: “The Implementation of Components”

Essential Reading Order

  1. The Foundation (Week 1):
    • Vue.js 3 Design and Implementation Ch. 4 (Reactivity)
    • MDN Documentation on Proxy and Reflect
  2. The Renderer (Week 2):
    • Vue.js 3 Design and Implementation Ch. 7 & 8 (Renderer & Patching)


Project 4: Computed Properties (Lazy Reactivity)

  • File: VUEJS_INTERNALS_REACTIVITY_MASTERY.md
  • Main Programming Language: JavaScript
  • Alternative Programming Languages: TypeScript
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 3: Advanced
  • Knowledge Area: Optimization / Caching
  • Software or Tool: Node.js
  • Main Book: “Vue.js 3 Design and Implementation” by Huo Chunyang

What you’ll build: A computed(getter) function that returns a read-only ref. It only re-calculates its value when its dependencies change, and it caches the result for subsequent accesses.

Why it teaches Vue internals: You’ll learn about “Lazy Effects.” You’ll see how Vue manages state internally with dirty flags and how an effect can be both a “subscriber” (to its dependencies) and a “publisher” (to effects that use the computed value).

Core challenges you’ll face:

  • Caching Logic → How to know when the cached value is “stale.”
  • Double Dependency Tracking → A computed property is used inside an effect, which is used inside another effect. How does the “chain of reactivity” work?
  • The dirty Flag → Implementing a scheduler to flip the flag without re-running the getter immediately.

Key Concepts:

  • Lazy Evaluation: “Vue.js 3 Design and Implementation” Ch. 4.5
  • Computed Scheduler: Using the scheduler option in effect.

Difficulty: Advanced Time estimate: 1-2 days Prerequisites: Completion of Projects 1, 2, and 3.


Real World Outcome

You’ll build a value that “knows” when it needs to be updated.

Example Output:

const price = ref(100);
const quantity = ref(2);

const total = computed(() => {
  console.log('Calculating total...');
  return price.value * quantity.value;
});

console.log(total.value); // Logs: Calculating total... 200
console.log(total.value); // (No log, returns cached 200)

price.value = 150;
console.log(total.value); // Logs: Calculating total... 300

The Core Question You’re Answering

“How can I avoid expensive calculations if the input data hasn’t changed?”

In a naive system, you’d re-calculate the total every time you ask for it. Computed properties solve this by subscribing to the inputs (price, quantity) and marking themselves as “dirty” only when those inputs change. They don’t actually run the calculation until you ask for the value.


Concepts You Must Understand First

Stop and research these before coding:

  1. Memoization
    • What is caching?
    • Why is it important in UI frameworks?
  2. Schedulers in Reactivity
    • What happens if we don’t run an effect immediately but instead let someone else decide when to run it?
    • Book Reference: “Vue.js 3 Design and Implementation” Ch. 4.5

Questions to Guide Your Design

  1. When to run?: Should the getter run immediately when computed() is called? (Vue says no—it’s lazy!).
  2. Where to store the value?: Where do you keep the cached result?
  3. The Scheduler: How do you notify the computed property that its dependencies changed without actually running the getter? (Hint: The Proxy’s set trap calls trigger, which should call a scheduler if it exists).

Thinking Exercise

The Dirty Flag

let dirty = true;
let value;

const effectFn = effect(() => {
  if (dirty) {
    value = getter();
    dirty = false;
  }
  return value;
}, {
  scheduler() {
    dirty = true; // Don't run effect, just mark it stale
  }
});

Questions:

  • When does value = getter() run?
  • If price.value changes 10 times, how many times does the scheduler run? How many times does the getter run?
  • Why is this more efficient than a regular effect?

The Interview Questions They’ll Ask

  1. “How do computed properties work in Vue 3?”
  2. “What is the role of the dirty flag in a computed property?”
  3. “Are computed properties eager or lazy? Why?”
  4. “Explain how computed properties handle caching.”
  5. “What happens if a computed property’s dependencies change but its value is never accessed?”

Hints in Layers

Hint 1: The Wrapper computed returns a ref-like object with a get value().

Hint 2: The Internal Effect Create an internal effect that wraps your getter. Use the lazy: true option (you’ll need to modify your Project 2 effect to support this).

Hint 3: The Scheduler Provide a scheduler to the internal effect. When the scheduler runs, it should set a _dirty variable to true and call trigger(this, 'value') to notify anyone listening to the computed property.

Hint 4: Tracking the Computed Inside the computed property’s get value(), you must call track(this, 'value') so that other effects (like a component render) can subscribe to this computed property.


Books That Will Help

Topic Book Chapter
Computed Implementation “Vue.js 3 Design and Implementation” Ch. 4.5

Implementation Hints

Computed properties are essentially “bridges.” They are an effect on one side (watching data) and a ref on the other side (providing data).

The key is that the getter should only run inside the get value() call, and only if _dirty is true. Once it runs, set _dirty = false.


Learning Milestones

  1. Basic getter works → Computed returns the correct value.
  2. Caching works → Accessing the value twice only calls the getter once.
  3. Reactivity works → Changing a dependency makes the computed property “dirty” and triggers dependent effects.

Project 5: Watch and WatchEffect (Side Effects)

  • File: VUEJS_INTERNALS_REACTIVITY_MASTERY.md
  • Main Programming Language: JavaScript
  • Alternative Programming Languages: TypeScript
  • Coolness Level: Level 2: Practical but Forgettable
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 3: Advanced
  • Knowledge Area: Async / Control Flow
  • Software or Tool: Node.js
  • Main Book: “Vue.js 3 Design and Implementation” by Huo Chunyang

What you’ll build: A watch(source, callback) and watchEffect(fn) function. It will allow users to perform side effects (like API calls) when reactive data changes, providing “old value” and “new value” comparisons.

Why it teaches Vue internals: You’ll learn how to traverse reactive objects to collect dependencies and how to handle asynchronous cleanups (the onCleanup pattern).

Core challenges you’ll face:

  • Recursive Traversal → If a user watches an entire object, how do you track every single property inside it?
  • Old vs. New Value → How do you capture the value before it changes?
  • Cleanup Functions → Handling race conditions in async tasks.

Key Concepts:

  • Object Traversal (traverse): “Vue.js 3 Design and Implementation” Ch. 4.7
  • Immediate and Post Flush: Timing the callback execution.
  • onCleanup Pattern: Handling side-effect expiration.

Difficulty: Advanced Time estimate: 2-3 days Prerequisites: Completion of Projects 1-4.


Real World Outcome

You’ll build a system that can trigger API calls or log changes automatically.

Example Output:

const state = reactive({ count: 0 });

watch(() => state.count, (newVal, oldVal) => {
  console.log(`Changed from ${oldVal} to ${newVal}`);
});

state.count++;
// Output: Changed from 0 to 1

The Core Question You’re Answering

“How can I perform an action after data changes, but with access to what the data was?”

Unlike effect, which just runs code, watch is designed for orchestration. It needs to know when to run, what exactly changed, and how to clean up after itself if the data changes again quickly.


Concepts You Must Understand First

Stop and research these before coding:

  1. Deep vs. Shallow Watching
    • Why is watching a whole object expensive?
    • What is “traversal”?
  2. Race Conditions
    • If two API calls are triggered by two rapid data changes, how do you make sure the older one doesn’t overwrite the newer one?

Questions to Guide Your Design

  1. The Source: Can your watch handle a ref, a reactive object, and a getter function () => state.count?
  2. Immediate: How would you implement the { immediate: true } option?
  3. Traversal: Write a function that recursively reads every property of an object to trigger all get traps.

Thinking Exercise

The Race to the Finish

Imagine this code:

watch(id, async (newId, oldId, onCleanup) => {
  let expired = false;
  onCleanup(() => expired = true);

  const data = await fetch(`/api/${newId}`);
  if (!expired) {
    updateUI(data);
  }
});

Questions:

  • If id changes from 1 to 2, then to 3 very quickly…
  • When id changes to 2, onCleanup for 1 is called.
  • When id changes to 3, onCleanup for 2 is called.
  • How does the expired flag prevent the UI from flickering with old data?

The Interview Questions They’ll Ask

  1. “What is the difference between watch and watchEffect?”
  2. “How does watch handle deep reactivity?”
  3. “Explain the onCleanup argument in Vue’s watch.”
  4. “How do you watch a specific property of a reactive object?”
  5. “What are ‘flush’ options in Vue watchers (pre, post, sync)?”

Hints in Layers

Hint 1: The Simple watchEffect watchEffect(fn) is just your effect(fn) function from Project 2!

Hint 2: The watch Source If the source is a function, use it as the effect’s getter. If it’s a reactive object, write a traverse function that reads every key.

Hint 3: Capturing Old Value Inside your effect, run the getter and store the result in oldValue. When the scheduler runs, run the getter again to get newValue, then call the user’s callback with both.

Hint 4: Cleanup Logic Maintain a cleanup variable. Before running the effect again, check if cleanup is a function. If so, call it. Provide a function to the user that lets them set this cleanup variable.


Books That Will Help

Topic Book Chapter
Watch Implementation “Vue.js 3 Design and Implementation” Ch. 4.7 - 4.11

Implementation Hints

The traverse function is recursive. Be careful with circular references! Use a Set to keep track of objects you’ve already visited during a single traversal.

For the watch callback, you need to use the scheduler you built in Project 4. The scheduler is what will actually trigger the user’s callback function.


Learning Milestones

  1. watchEffect works → Basic side effects trigger.
  2. watch with old/new values works → Callback receives the correct arguments.
  3. Deep watch works → Changing a nested property triggers the watcher.

Project 6: Simple Virtual DOM Renderer (The Blueprint)

  • File: VUEJS_INTERNALS_REACTIVITY_MASTERY.md
  • Main Programming Language: JavaScript
  • Alternative Programming Languages: TypeScript
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 2: Intermediate
  • Knowledge Area: DOM Manipulation / Data Structures
  • Software or Tool: Browser
  • Main Book: “Vue.js 3 Design and Implementation” by Huo Chunyang

What you’ll build: An h(tag, props, children) function to create Virtual Nodes (VNodes) and a mount(vnode, container) function that turns those VNodes into real HTML elements.

Why it teaches Vue internals: You’ll move from “data” to “UI.” You’ll learn exactly what a VNode is (just a JS object) and how Vue translates abstract descriptions into physical DOM nodes.

Core challenges you’ll face:

  • Props Handling → Distinguishing between HTML attributes (like id), DOM properties (like value), and Event Listeners (like onClick).
  • Recursive Mounting → How to render children that are also VNodes.
  • Efficient Creation → Making sure your VNode object is lightweight.

Key Concepts:

  • VNode Structure: “Vue.js 3 Design and Implementation” Ch. 7.2
  • The h Function: Hyperscript basics.
  • Mounting Process: document.createElement, el.setAttribute, container.appendChild.

Difficulty: Intermediate Time estimate: 1 day Prerequisites: Basic knowledge of browser DOM APIs.


Real World Outcome

You’ll build a way to describe HTML using only JavaScript objects.

Example Output:

const vnode = h('div', { id: 'app' }, [
  h('h1', { class: 'title' }, 'Hello VDOM'),
  h('button', { onClick: () => alert('hi') }, 'Click Me')
]);

mount(vnode, document.body);
// Result: A div with an h1 and a button appears on your screen!

The Core Question You’re Answering

“Why don’t we just use document.createElement directly? Why the extra object?”

Directly touching the DOM is expensive and hard to track. By creating a JavaScript “blueprint” (the VNode) first, we can compare two blueprints (Project 7) and find the minimal changes needed. It also allows Vue to run on platforms without a DOM (like Canvas or Mobile).


Concepts You Must Understand First

Stop and research these before coding:

  1. The Browser DOM API
    • What is the difference between setAttribute and el.id = ...?
    • How do you add an event listener programmatically?
  2. JSON-like Data Structures
    • How can you represent a tree structure using only arrays and objects?

Questions to Guide Your Design

  1. VNode Shape: What properties does your VNode need? (type, props, children, el…). Why do we store the real el on the VNode?
  2. Prop Logic: How do you detect if a prop is an event listener? (Hint: Does it start with “on”?).
  3. Text Nodes: How do you handle a VNode that is just a string of text instead of an element?

Thinking Exercise

The Object Mirror

Look at this HTML:

<div class="container">
  <span>Hello</span>
</div>

Questions:

  • Write a JavaScript object that represents this perfectly.
  • If you change the text to “Goodbye”, how would you change your object?
  • What’s faster: updating a string in your object, or calling span.textContent = 'Goodbye' in the browser? (The object update is thousands of times faster).

The Interview Questions They’ll Ask

  1. “What is a VNode in Vue 3?”
  2. “How does the h() function work?”
  3. “Why does Vue use a Virtual DOM instead of direct DOM manipulation?”
  4. “What information is stored inside a VNode?”
  5. “Explain the process of mounting a VNode to the DOM.”

Hints in Layers

Hint 1: The h Function It just returns an object: { type, props, children }. Don’t overthink it.

Hint 2: The mount Function Use document.createElement(vnode.type). Then loop through vnode.props and apply them to the element. Finally, loop through vnode.children. If a child is a string, set textContent. If it’s another VNode, call mount recursively.

Hint 3: Props and Events Inside mount, check if the key starts with on. If it does, use el.addEventListener(key.slice(2).toLowerCase(), value).

Hint 4: Storing the Element Crucial step: After you create the element, store it on the VNode: vnode.el = el. You’ll need this for patching later!


Books That Will Help

Topic Book Chapter
VDOM Implementation “Vue.js 3 Design and Implementation” Ch. 7 & 8
DOM APIs “Eloquent JavaScript” Ch. 14

Implementation Hints

For props, remember that some things are “attributes” (in the HTML) and some are “properties” (on the JS object). For example, class in HTML maps to className in JS. Vue handles this with a “patchProps” utility. For your project, just focus on setAttribute and basic property assignment.


Learning Milestones

  1. h function works → You can create nested VNode objects.
  2. Mounting works → Static HTML is generated in the browser.
  3. Events work → Buttons created via VDOM can trigger alerts.

Project 7: The Patching Algorithm (The Diff)

  • File: VUEJS_INTERNALS_REACTIVITY_MASTERY.md
  • Main Programming Language: JavaScript
  • Alternative Programming Languages: TypeScript
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 3: Advanced
  • Knowledge Area: Optimization / Sequence Alignment
  • Software or Tool: Browser
  • Main Book: “Vue.js 3 Design and Implementation” by Huo Chunyang

What you’ll build: A patch(n1, n2, container) function. If n1 (old VNode) is null, it mounts. If n1 exists, it compares n1 and n2 and only updates what’s different (text content or props).

Why it teaches Vue internals: This is the core of the “Virtual DOM” value proposition. You’ll learn how Vue avoids recreating the entire DOM tree and instead “patches” existing elements in place.

Core challenges you’ll face:

  • Identity Check → How do you know if two VNodes represent the “same” element? (Hint: Type and Key).
  • Prop Patching → Efficiently updating attributes while removing those that are no longer present in the new VNode.
  • Node Reuse → Realizing that the real DOM element el must be passed from the old VNode to the new one.

Key Concepts:

  • Patching Process: “Vue.js 3 Design and Implementation” Ch. 8.1
  • Updating Props: “Vue.js 3 Design and Implementation” Ch. 8.2

Difficulty: Advanced Time estimate: 2-3 days Prerequisites: Completion of Project 6.


Real World Outcome

You’ll have a renderer that can update the UI without causing a full page flicker or losing focus in an input field.

Example Output:

const v1 = h('div', { id: 'foo' }, 'Hello');
const v2 = h('div', { id: 'bar' }, 'Vue');

mount(v1, document.body); 
// Real DOM: <div id="foo">Hello</div>

patch(v1, v2, document.body);
// Real DOM is UPDATED to: <div id="bar">Vue</div>
// Notice: The <div> element was REUSED, not recreated!

The Core Question You’re Answering

“How can I update only the parts of the page that changed without resetting the whole screen?”

If you just do innerHTML = ..., you lose the user’s cursor position in an input, you break CSS transitions, and it’s slow. Patching solves this by surgically updating attributes and text content while keeping the actual DOM nodes alive.


Concepts You Must Understand First

Stop and research these before coding:

  1. DOM Persistence
    • What happens to an <input> if you remove it from the DOM and re-add it?
    • Why is it important to keep the same object reference for DOM elements?
  2. Attribute vs Property (again)
    • How do you “remove” an attribute that is no longer in the props object?

Questions to Guide Your Design

  1. The Handover: When patch finds that two VNodes are the same type, how does the new VNode get access to the el created by the old VNode?
  2. Text Update: If vnode.children is a string, and it changed, what is the most efficient DOM command to update it?
  3. Prop Diffing: If the old props are { a: 1, b: 2 } and the new props are { a: 2, c: 3 }, what three actions must you take?

Thinking Exercise

The Surgical Strike

Imagine you have a list of 1,000 items. You change the color of the 500th item.

Questions:

  • In a “re-mount everything” strategy, how many DOM nodes are created? (1,000+).
  • In a “patching” strategy, how many DOM nodes are created? (Zero).
  • How many DOM properties are modified? (Exactly one).
  • Why is the VDOM approach better for the user’s battery life?

The Interview Questions They’ll Ask

  1. “Explain the patching process in Vue 3.”
  2. “How does Vue decide whether to reuse a DOM element or replace it?”
  3. “What happens if the type of a VNode changes during a patch (e.g., div to span)?”
  4. “How do you handle props that exist in the old VNode but are missing in the new one?”
  5. “What is the relationship between VNodes and real DOM elements during the patch phase?”

Hints in Layers

Hint 1: The Identity Check Inside patch, if n1.type !== n2.type, you can’t patch. You must unmount n1 and mount n2.

Hint 2: Reusing the Element If they are the same type, set const el = n2.el = n1.el. Now all your updates will happen on this same element.

Hint 3: Patching Props Loop through the new props and set them on el. Then, loop through the old props; if a key is not in the new props, remove it from el.

Hint 4: Patching Children For this project, assume children are just strings. Compare n1.children and n2.children. If they are different, update el.textContent.


Books That Will Help

Topic Book Chapter
Patching Strategy “Vue.js 3 Design and Implementation” Ch. 8

Implementation Hints

When patching props, remember your event listener logic from Project 6. If a listener changed (e.g., onClick points to a new function), you need to removeEventListener the old one and addEventListener the new one. Vue actually uses a “invoker” trick to make this faster—check Ch. 8.2 of the book!


Learning Milestones

  1. Prop patching works → Element IDs and classes update without recreation.
  2. Text patching works → Text updates correctly.
  3. Unmounting works → If types change, the old element is removed and the new one is inserted.

Project 8: List Diffing with Keys (The “Hard” Part)

  • File: VUEJS_INTERNALS_REACTIVITY_MASTERY.md
  • Main Programming Language: JavaScript
  • Alternative Programming Languages: TypeScript
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 5: Master
  • Knowledge Area: Algorithms / Longest Increasing Subsequence
  • Software or Tool: Browser
  • Main Book: “Vue.js 3 Design and Implementation” by Huo Chunyang

What you’ll build: A complex patchChildren function that handles arrays of VNodes. It will use “Keys” to identify which items moved, which were added, and which were removed.

Why it teaches Vue internals: This is the “brain” of the Virtual DOM. You’ll learn why using index as a key is a bad idea and how Vue uses the “Longest Increasing Subsequence” algorithm to minimize element movements.

Core challenges you’ll face:

  • Identifying Moved Nodes → Mapping old indices to new indices using keys.
  • Minimizing DOM Movesel.insertBefore is expensive. How do you find the fewest number of moves to reach the new state?
  • Handling Edge Cases → Adding items to the beginning, end, or middle of the list.

Key Concepts:

  • Simple Diffing: “Vue.js 3 Design and Implementation” Ch. 9
  • Double-Ended Diffing: “Vue.js 3 Design and Implementation” Ch. 10
  • Fast Diffing (LIS): “Vue.js 3 Design and Implementation” Ch. 11

Difficulty: Master Time estimate: 1 week Prerequisites: Completion of Project 7, knowledge of basic data structures (Maps).


Real World Outcome

You’ll build a list that can re-order 1,000 items instantly without flickering or losing state.

Example Output:

const oldList = [
  h('li', { key: 'a' }, 'A'),
  h('li', { key: 'b' }, 'B'),
  h('li', { key: 'c' }, 'C')
];

const newList = [
  h('li', { key: 'c' }, 'C'),
  h('li', { key: 'a' }, 'A'),
  h('li', { key: 'b' }, 'B')
];

patch(oldList, newList, container);
// Result: Node 'C' is moved to the top. 'A' and 'B' are NOT touched.

The Core Question You’re Answering

“If I move an item from the bottom of a list to the top, how does the framework know not to delete and recreate everything?”

Without keys, Vue just sees “the first item changed its text.” With keys, Vue understands “the item with ID ‘c’ moved.” This distinction is the difference between a broken UI (where an input loses focus) and a perfect UI.


Concepts You Must Understand First

Stop and research these before coding:

  1. The “Key” Property
    • Why is key special?
    • What happens if you have duplicate keys?
  2. Longest Increasing Subsequence (LIS)
    • What is this algorithm?
    • How does it help in finding which nodes don’t need to move?

Questions to Guide Your Design

  1. The Map: How can you use a Map of key -> index to speed up finding nodes in the old list?
  2. The Move Logic: If an item’s new index is 2, but its “max observed old index” so far was 5, does that mean this item moved?
  3. The Anchor: When inserting a new node, how do you find the “anchor” node (the node it should be inserted before)?

Thinking Exercise

The Library Re-organization

Imagine a shelf of books. You want to move the 10th book to the 1st position.

Questions:

  • If you take all books off the shelf and put them back one by one, how much work is that?
  • If you just pull the 10th book out and slide it into the 1st spot, how much work is that?
  • How would you write down the minimum set of instructions for someone else to transform the old shelf into the new shelf?

The Interview Questions They’ll Ask

  1. “Why is it dangerous to use index as a key in v-for?”
  2. “Explain how Vue 3’s diffing algorithm works for children.”
  3. “What is the Longest Increasing Subsequence (LIS) and how is it used in Vue?”
  4. “Compare ‘Simple Diffing’ vs ‘Double-Ended Diffing’.”
  5. “How does Vue handle adding/removing multiple items in one update?”

Hints in Layers

Hint 1: The Simple Loop First, try a naive approach: Loop through the new children. For each one, look for its key in the old children. If you find it, patch it and move it to the right place.

Hint 2: Detecting Moves Keep a variable lastIndex = 0. As you loop through new children, find their index in the old list. If oldIndex < lastIndex, the node has moved. If oldIndex >= lastIndex, update lastIndex = oldIndex.

Hint 3: The Anchor To move a node, use container.insertBefore(node.el, anchorNode.el). The anchor is usually the el of the next sibling in the new list.

Hint 4: The LIS Optimization For the full Vue 3 “Fast Diff” algorithm, you need to build a source array where source[newIndex] = oldIndex. Then, find the LIS of source. The indices in the LIS are the nodes that stay put. Move everything else.


Books That Will Help

Topic Book Chapter
List Diffing Algorithms “Vue.js 3 Design and Implementation” Ch. 9, 10, 11
LIS Algorithm “Introduction to Algorithms” (CLRS) Ch. 15.4

Implementation Hints

This is the most algorithmically intense project. Don’t worry if you don’t get the LIS part right away. Start with the “Simple Diff” (Ch. 9) first. Once that works, you’ll understand the problem well enough to appreciate the LIS optimization.


Learning Milestones

  1. Key-based patching works → Elements are reused based on keys.
  2. Add/Remove works → New items appear and old ones vanish.
  3. Move logic works → Items change position without being recreated (test this with an <input> in the list).

Project 9: The Scheduler (Batching Updates)

  • File: VUEJS_INTERNALS_REACTIVITY_MASTERY.md
  • Main Programming Language: JavaScript
  • Alternative Programming Languages: TypeScript
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 3: Advanced
  • Knowledge Area: Event Loop / Microtasks
  • Software or Tool: Browser / Node.js
  • Main Book: “Vue.js 3 Design and Implementation” by Huo Chunyang

What you’ll build: A global queue system that batches multiple state changes into a single DOM update using Promise.resolve().then().

Why it teaches Vue internals: You’ll learn why nextTick() exists. You’ll understand the “asynchronous” nature of Vue’s rendering and how it prevents “layout thrashing” by grouping DOM writes together.

Core challenges you’ll face:

  • Deduplication → If an effect is triggered 5 times in one millisecond, it should only run once in the next tick.
  • Ordering → Making sure parent components update before child components.
  • The Event Loop → Understanding exactly when a microtask runs compared to a regular function.

Key Concepts:

  • Queueing Jobs: “Vue.js 3 Design and Implementation” Ch. 4.6
  • Microtasks: queueMicrotask or Promise.resolve().

Difficulty: Advanced Time estimate: 2 days Prerequisites: Completion of Project 2 (Effect) and Project 7 (Patch).


Real World Outcome

You’ll build a UI that stays responsive even if you update the state thousands of times in a loop.

Example Output:

const state = reactive({ count: 0 });

effect(() => {
  console.log('Rendering UI with count:', state.count);
  render(state.count);
});

// Update state 100 times in a row
for (let i = 0; i < 100; i++) {
  state.count++;
}

// Without scheduler: "Rendering UI..." prints 101 times.
// With scheduler: "Rendering UI..." prints 2 times (once at start, once at end).

The Core Question You’re Answering

“If I update 10 variables in a single function, why doesn’t Vue re-render the screen 10 times?”

Re-rendering the screen is the most expensive thing a browser does. If we did it synchronously on every change, the app would lag. The scheduler acts as a “waiting room” where updates are collected and then executed all at once at the end of the current task.


Concepts You Must Understand First

Stop and research these before coding:

  1. The JavaScript Event Loop
    • What is a Macrotask (setTimeout)?
    • What is a Microtask (Promise)?
    • When does the browser “paint” the screen?
  2. Deduplication
    • How can you use a Set to ensure a function is only in a queue once?

Questions to Guide Your Design

  1. The Queue: How do you store the jobs? A Set is great for deduplication, but is it good for ordering?
  2. Flushing: How do you tell the browser “Hey, run this queue as soon as you’re done with the current code”?
  3. nextTick: How would you implement a function that lets the user run code after the scheduler has finished its work?

Thinking Exercise

The Batching Benefit

let count = 0;
function update() { console.log('Update!'); }

function trigger() {
  // Push update to a queue instead of running it
  queueJob(update);
}

trigger();
trigger();
trigger();
console.log('Main code finished');

Questions:

  • If queueJob uses a microtask, what is the order of console logs?
  • How many times does Update! print?
  • Why is it important that the trigger() calls finish before the first update() runs?

The Interview Questions They’ll Ask

  1. “Why are Vue’s DOM updates asynchronous?”
  2. “How would you implement nextTick from scratch?”
  3. “What is the difference between a microtask and a macrotask in the context of Vue’s scheduler?”
  4. “How does Vue prevent parent and child components from re-rendering multiple times in one tick?”
  5. “What happens if you modify the state inside a nextTick callback?”

Hints in Layers

Hint 1: The Queue Create a const queue = new Set(). When an effect needs to run, instead of calling it, add it to the queue.

Hint 2: The Flush Create a let isFlushing = false. When you add something to the queue, if !isFlushing, set isFlushing = true and call Promise.resolve().then(flushQueue).

Hint 3: flushQueue Inside flushQueue, loop through the queue and execute every job. Then clear the queue and set isFlushing = false.

Hint 4: nextTick nextTick(fn) should just return Promise.resolve().then(fn). Because it’s added to the microtask queue after the scheduler’s flush was added, it will naturally run after the flush finishes.


Books That Will Help

Topic Book Chapter
Scheduler Implementation “Vue.js 3 Design and Implementation” Ch. 4.6
Event Loop “You Don’t Know JS: Async & Performance” by Kyle Simpson Ch. 1

Implementation Hints

In a real framework, the scheduler also handles errors (so one failing component doesn’t stop the whole queue) and manages priorities. For this project, focus on the basic Set-based deduplication and the Promise based flushing.


Learning Milestones

  1. Updates are asynchronous → State changes don’t cause immediate console logs.
  2. Batching works → Multiple changes only cause one log.
  3. nextTick works → You can access the “updated” DOM (or state) inside a nextTick callback.

Project 10: Component System (The Abstraction)

  • File: VUEJS_INTERNALS_REACTIVITY_MASTERY.md
  • Main Programming Language: JavaScript
  • Alternative Programming Languages: TypeScript
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 4: Expert
  • Knowledge Area: Software Architecture / Encapsulation
  • Software or Tool: Browser
  • Main Book: “Vue.js 3 Design and Implementation” by Huo Chunyang

What you’ll build: Support for “Component VNodes” (where vnode.type is an object, not a string). You’ll implement the setup and render functions, and manage the component’s internal state and lifecycle.

Why it teaches Vue internals: You’ll learn how Vue manages local state within a global reactivity system. You’ll understand the “Component Instance” and how this (or the setup context) is wired up.

Core challenges you’ll face:

  • Component Lifecycle → When to run setup, when to run the initial render, and when to patch the component’s subtree.
  • Props Resolution → How to pass data from a parent component down to a child.
  • Instance Management → Creating a “Component Instance” object to store state, props, and the Virtual DOM tree.

Key Concepts:

  • Component Implementation: “Vue.js 3 Design and Implementation” Ch. 12
  • The Setup Function: “Vue.js 3 Design and Implementation” Ch. 13
  • Props and Emit: Handling communication.

Difficulty: Expert Time estimate: 4-5 days Prerequisites: Completion of Projects 1-9.


Real World Outcome

You’ll be able to create reusable blocks of UI with their own private state.

Example Output:

const MyComponent = {
  setup() {
    const count = ref(0);
    return { count };
  },
  render(state) {
    return h('button', { onClick: () => state.count++ }, `Count: ${state.count}`);
  }
};

// Use it like a regular tag!
mount(h(MyComponent), document.body);

The Core Question You’re Answering

“How does a framework manage thousands of different pieces of state without them clashing?”

Components are the solution to scaling. Each component instance is like a “mini-app” with its own effect for rendering. When a component’s state changes, only that component’s render effect is added to the scheduler, making updates highly efficient and localized.


Concepts You Must Understand First

Stop and research these before coding:

  1. Closure and State Scope
    • How does the setup() function keep its variables private?
    • How do we “expose” variables to the render function?
  2. The “Subtree” Concept
    • A component doesn’t render DOM nodes directly. It renders another VNode (the subtree).
    • How does patch handle the transition from a component VNode to its subtree?

Questions to Guide Your Design

  1. Instance Object: What properties do you need on the instance? (props, state, isMounted, subtree…).
  2. Mounting: When mount sees vnode.type is an object, what is the first thing it should do? (Hint: Create the instance).
  3. Updating: If a component’s props change, how do you trigger a re-render of the child? (Hint: The parent’s patch call should update the child instance’s props).

Thinking Exercise

The Effect Nesting

Imagine Component A contains Component B.

Questions:

  • When Component A re-renders, does Component B’s setup run again? (No).
  • Does Component B’s render run again? (Only if its props changed).
  • How does Vue ensure that A’s render effect finishes before B’s render effect starts? (Ordering in the Scheduler).

The Interview Questions They’ll Ask

  1. “What is a component instance in Vue 3?”
  2. “How does the setup() function differ from the data() option internally?”
  3. “Explain how Vue handles component updates when props change.”
  4. “Why does each component have its own render effect?”
  5. “How does ‘emit’ work? How does a child notify a parent?”

Hints in Layers

Hint 1: The Instance Create a function createInternalInstance(vnode). It should return an object with vnode, type (the component object), props, setupState, etc.

Hint 2: Initial Mount In mountComponent, call type.setup(). Take the returned object (setupState) and pass it to type.render(setupState). The result of the render is the subTree. Now, recursively call patch(null, subTree, container).

Hint 3: The Update Effect Wrap the “render and patch” logic inside an effect. This way, whenever setupState (which contains refs) changes, the component automatically re-renders its subtree!

Hint 4: Storing the Subtree Save the subTree on the instance: instance.subTree = subTree. When the component updates, call patch(oldSubTree, newSubTree). This is where your VDOM diffing from Project 7 comes in!


Books That Will Help

Topic Book Chapter
Component Implementation “Vue.js 3 Design and Implementation” Ch. 12

Implementation Hints

Component props are “reactive but read-only” from the child’s perspective. In your implementation, you can just pass the props object through shallowReactive().

Make sure your mount and patch functions are updated to check typeof vnode.type === 'object' to distinguish components from regular HTML elements.


Learning Milestones

  1. Static component works → A component renders its template once.
  2. Reactive component works → Changing state inside setup triggers a re-render.
  3. Props work → A parent component can pass data to a child and update it.

Project 11: Template Parser (From HTML to AST)

  • File: VUEJS_INTERNALS_REACTIVITY_MASTERY.md
  • Main Programming Language: JavaScript
  • Alternative Programming Languages: TypeScript
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 4: Expert
  • Knowledge Area: Parsing / Finite State Machines
  • Software or Tool: Node.js
  • Main Book: “Vue.js 3 Design and Implementation” by Huo Chunyang

What you’ll build: A parse(template) function that takes a string like "<div id='app'>{{ msg }}</div>" and converts it into a JavaScript object tree called an Abstract Syntax Tree (AST).

Why it teaches Vue internals: You’ll understand how Vue reads your code. You’ll learn about “Tokenization” and how to build a recursive descent parser that handles tags, attributes, and interpolation.

Core challenges you’ll face:

  • Tokenizing the String → Using a State Machine to distinguish between start tags, end tags, text, and {{ }} markers.
  • Stack-based Tree Building → Using a stack to keep track of open tags to ensure the tree structure is correct.
  • Error Handling → What happens if the user forgets to close a </div>?

Key Concepts:

  • Tokenization: “Vue.js 3 Design and Implementation” Ch. 15.2
  • Recursive Descent: Building the tree from tokens.
  • AST Nodes: Representing elements, text, and expressions.

Difficulty: Expert Time estimate: 3-4 days Prerequisites: Completion of Projects 1-10.


Real World Outcome

You’ll have a tool that “understands” the structure of a template string.

Example Output:

const ast = parse('<div id="app">Hello {{ name }}</div>');

/*
Output:
{
  type: 'Root',
  children: [
    {
      type: 'Element',
      tag: 'div',
      props: [{ name: 'id', value: 'app' }],
      children: [
        { type: 'Text', content: 'Hello ' },
        { type: 'Interpolation', content: 'name' }
      ]
    }
  ]
}
*/

The Core Question You’re Answering

“How does a string of characters become an interactive program?”

Browsers don’t know what {{ msg }} means. The compiler must first “read” the template character by character, recognize the patterns (the {{ and }}), and build a data structure (the AST) that the next stages of the compiler can analyze.


Concepts You Must Understand First

Stop and research these before coding:

  1. Finite State Machines (FSM)
    • What are “States” and “Transitions”?
    • How can you use a while loop and a switch statement to parse text?
  2. Recursive Descent Parsing
    • How do you parse nested structures (tags inside tags) using functions that call themselves?

Questions to Guide Your Design

  1. State Machine: What states do you need? (Initial, TagOpen, TagName, AttrName, AttrValue, Text…).
  2. Consumption: As you parse, how do you “consume” the string so you don’t process the same character twice? (Hint: Use slice() or an index pointer).
  3. The Stack: When you see <div>, you push it onto the stack. When you see </div>, you pop it. Why is this necessary?

Thinking Exercise

The Token Stream

Look at the string: <div>Hi</div>

Tokens:

  1. Start Tag: div
  2. Text: Hi
  3. End Tag: div

Questions:

  • If the string was <div><span>Hi</span></div>, what are the tokens?
  • How do you know <span> is a child of <div>?
  • How would you handle a self-closing tag like <br />?

The Interview Questions They’ll Ask

  1. “What is an AST (Abstract Syntax Tree)?”
  2. “Explain the difference between a Lexer (Tokenizer) and a Parser.”
  3. “How does Vue’s parser handle malformed HTML (e.g., unclosed tags)?”
  4. “Why is a stack used during the parsing process?”
  5. “How does the parser recognize Vue-specific directives like v-if or v-for?”

Hints in Layers

Hint 1: The Tokenizer Start with a loop while (template). Use regular expressions to find the next “thing” (a tag, text, or interpolation). Slice the template as you find things.

Hint 2: Tag Parsing When you find a <[a-z]+, enter a “Tag Parsing” mode. Look for attributes until you find a >.

Hint 3: The Tree Stack Maintain a const stack = []. When you parse a start tag, create an AST node, add it to the children of the current top of the stack, and then push the new node onto the stack. When you see an end tag, pop from the stack.

Hint 4: Interpolation Look for {{. Capture everything until the next }}. Create a node of type Interpolation.


Books That Will Help

Topic Book Chapter
Template Parsing “Vue.js 3 Design and Implementation” Ch. 15
Parsing Theory “Engineering a Compiler” Ch. 3

Implementation Hints

Parsing is all about string manipulation. Use template.startsWith() and template.match() heavily. To keep it simple, focus on standard HTML first. Don’t worry about complex directives until the basic tree structure works.


Learning Milestones

  1. Tokenization works → You can identify tags and text in a string.
  2. Tree structure works → Nested tags are correctly represented in the AST.
  3. Interpolation works{{ }} expressions are correctly identified.

Project 12: Template Transformer (The Optimizer)

  • File: VUEJS_INTERNALS_REACTIVITY_MASTERY.md
  • Main Programming Language: JavaScript
  • Alternative Programming Languages: TypeScript
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 4: Expert
  • Knowledge Area: Optimization / Tree Traversal
  • Software or Tool: Node.js
  • Main Book: “Vue.js 3 Design and Implementation” by Huo Chunyang

What you’ll build: A transform(ast) function that traverses your AST and applies optimizations like “Static Hoisting” and adding “Patch Flags.”

Why it teaches Vue internals: This is where Vue 3 gets its speed. You’ll learn how the compiler helps the renderer by pre-analyzing the template. You’ll understand the concept of “Compiler-Informed Virtual DOM.”

Core challenges you’ll face:

  • Static Analysis → How do you determine if a branch of the AST is “static” (never changes)?
  • Patch Flags → Attaching metadata to nodes (e.g., “This div only ever changes its text”) so the renderer can skip prop-diffing later.
  • AST Transformation → Modifying the tree structure or adding new properties to nodes without breaking them.

Key Concepts:

  • Transform Context: Managing shared state during traversal.
  • Static Hoisting: Moving constant VNodes out of the render function.
  • Patch Flags: Bitwise flags for optimized diffing.

Difficulty: Expert Time estimate: 3 days Prerequisites: Completion of Project 11.


Real World Outcome

You’ll have an AST that contains “hints” for the renderer, allowing it to bypass 80% of the diffing work.

Example Output:

const ast = parse('<div><p>Static</p><span>{{ msg }}</span></div>');
transform(ast);

// The <p> node is marked as 'isStatic: true'
// The <span> node is given a 'patchFlag: 1' (TEXT)

The Core Question You’re Answering

“How can we make a Virtual DOM as fast as Svelte (which has no Virtual DOM)?”

By analyzing the template at compile-time, we can identify which parts are constant. We don’t need to diff a paragraph that says “Hello World” every time the state changes. We can just skip it!


Concepts You Must Understand First

Stop and research these before coding:

  1. Tree Traversal (Depth-First Search)
    • How do you visit every node in a tree?
    • What is the difference between “enter” and “exit” phases?
  2. Bitwise Operations
    • How do patch flags like 1 << 0 (TEXT) and 1 << 1 (CLASS) work?
    • Why are they faster than checking object properties?

Questions to Guide Your Design

  1. Visitor Pattern: Can you create a system where different “plugins” can handle different node types? (e.g., a transformElement plugin, a transformText plugin).
  2. Stateless vs Stateful: How do you know if a node is static? (Hint: It’s static if it has no directives and all its children are static).
  3. Exit Functions: Why might you want to perform an action on a node after you’ve finished visiting all its children?

Thinking Exercise

The Hoisting Benefit

Look at this render function pseudocode:

function render() {
  const p = h('p', null, 'Static Text'); // Created every time!
  const span = h('span', null, this.msg);
  return h('div', null, [p, span]);
}

Questions:

  • How would you move the p constant outside the render function?
  • If you move it outside, how many times is h('p'...) called during the app’s life?
  • If this.msg changes 1,000 times, how much memory do you save by hoisting?

The Interview Questions They’ll Ask

  1. “What is Static Hoisting in Vue 3?”
  2. “How do Patch Flags optimize the Virtual DOM?”
  3. “Explain the transformation phase of the Vue compiler.”
  4. “How does Vue identify a static node during compilation?”
  5. “What is ‘Tree Flattening’ (Block Tree) in Vue 3?”

Hints in Layers

Hint 1: The Traverser Create a function traverseNode(node, context). It should call context.nodeTransforms on the current node, then recursively call traverseNode on its children.

Hint 2: Static Analysis A node is “static” if its type is TEXT, or if it’s an ELEMENT with no dynamic props and all its children are static. Add an isStatic property to your AST nodes.

Hint 3: Hoisting When a node is static, move its description into a hoists array in the root AST node. Replace the node in the tree with a “Hoisted” placeholder.

Hint 4: Patch Flags If an element has interpolation in its children, mark it with the TEXT patch flag. If it has dynamic class bindings, mark it with the CLASS flag.


Books That Will Help

Topic Book Chapter
Compiler Transformation “Vue.js 3 Design and Implementation” Ch. 16
Bitwise Operations “The Secret Life of Programs” Ch. 1

Implementation Hints

Vue uses a “context” object during transformation to store the current parent, the current index, and the list of transforms. This makes it easy to replace or remove nodes during the traversal. For patch flags, use a simple object with numeric constants: PatchFlags = { TEXT: 1, CLASS: 2, ... }.


Learning Milestones

  1. Traversal works → You can visit and log every node in the AST.
  2. Static detection works → Static nodes are correctly identified.
  3. Patch flags work → Dynamic nodes receive the correct hints for the renderer.

Project 13: Render Function Generator (The Code Gen)

  • File: VUEJS_INTERNALS_REACTIVITY_MASTERY.md
  • Main Programming Language: JavaScript
  • Alternative Programming Languages: TypeScript
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 5: Master
  • Knowledge Area: Code Generation / String Manipulation
  • Software or Tool: Node.js
  • Main Book: “Vue.js 3 Design and Implementation” by Huo Chunyang

What you’ll build: A generate(ast) function that takes your optimized AST and returns a string of JavaScript code. This code, when executed (via new Function()), will be a valid Vue render function.

Why it teaches Vue internals: You’ll close the loop. You’ll see how a template like <div>{{ msg }}</div> becomes a function like return h('div', null, [msg]). You’ll understand how the compiler bridges the gap between static strings and dynamic JavaScript.

Core challenges you’ll face:

  • Expression Mapping → Turning AST nodes (like Interpolation) into valid JavaScript code (like variable access).
  • String Building → Managing indentation and commas to ensure the generated code is readable and syntactically correct.
  • Handling Hoists → Generating the code for hoisted variables outside the main function body.

Key Concepts:

  • Codegen Context: Managing the output string.
  • Helper Functions: Mapping AST types to function calls (like _h()).
  • Function Constructor: Dynamically creating a function from a string.

Difficulty: Master Time estimate: 4-5 days Prerequisites: Completion of Projects 11 and 12.


Real World Outcome

You’ll have a function that “writes” a program for you.

Example Output:

const ast = parse('<div>{{ msg }}</div>');
const code = generate(ast);

console.log(code);
/*
Output:
"const { h: _h } = Vue
return function render(_ctx) {
  return _h('div', null, [_ctx.msg])
}"
*/

const render = new Function('Vue', code)(VueInternals);

The Core Question You’re Answering

“How does Vue turn a template into a high-performance function?”

The final step of the compiler is translation. We’ve parsed the structure and optimized the nodes; now we just need to “print” them out in a format that the JavaScript engine can execute. This is where the “magic” of templates finally becomes standard code.


Concepts You Must Understand First

Stop and research these before coding:

  1. The new Function() Constructor
    • How can you turn a string of text into a runnable function at runtime?
    • What are the security implications?
  2. JavaScript String Interpolation
    • How to build large blocks of text with dynamic parts.

Questions to Guide Your Design

  1. Context: How do you handle variables? If the template says {{ msg }}, should the generated code say msg or _ctx.msg? (Hint: Vue uses _ctx to refer to the component’s state).
  2. Helpers: How do you avoid repeating long function names like createElementVNode? (Hint: Map them to short aliases like _h).
  3. Children: When generating code for an element, how do you handle the recursion for its children?

Thinking Exercise

The Code Mirror

Look at this AST snippet: { type: 'Element', tag: 'div', children: [{ type: 'Text', content: 'Hi' }] }

Questions:

  • What is the equivalent JavaScript code using your h() function?
  • If you have 10 children, how do you generate the array [...] in your code string?
  • How do you handle a child that is an Interpolation node instead of a Text node?

The Interview Questions They’ll Ask

  1. “How does Vue 3 generate render functions from templates?”
  2. “Why does the generated code use a _ctx prefix for variables?”
  3. “What are the advantages of pre-compiling templates vs. compiling them in the browser?”
  4. “How are ‘Hoisted’ nodes handled in the generated code?”
  5. “Explain how the code generator handles nested VNode calls.”

Hints in Layers

Hint 1: The Buffer Create a context object with a code string and a push(s) method.

Hint 2: The Structure Start by pushing the preamble: const { h: _h } = Vue; return function render(_ctx) { return . Then, call a function genNode(ast.root, context). Finally, push ` }`.

Hint 3: Generating Elements In genNode, if the type is Element, push _h('${node.tag}', . Then, generate the props (this is tricky—you’ll need to turn the props array back into a JS object string). Then, generate the children.

Hint 4: Generating Interpolations If the type is Interpolation, push _ctx.${node.content}. This ensures the function looks for the variable on the component instance.


Books That Will Help

Topic Book Chapter
Code Generation “Vue.js 3 Design and Implementation” Ch. 17
Metaprogramming “JavaScript: The Good Parts” by Douglas Crockford Ch. 4

Implementation Hints

Keep your indentation tidy! Add a context.indent() and context.deindent() method that adds spaces to every push(). This will make debugging your generated code much easier. Also, use a Map to store the mapping between AST types and generator functions.


Learning Milestones

  1. Simple generation works → A static tag becomes a valid h() call.
  2. Recursive generation works → Nested tags become nested h() calls.
  3. Reactive generation works → Templates with {{ }} become functions that access _ctx.

Project 14: Dependency Injection (Provide/Inject)

  • File: VUEJS_INTERNALS_REACTIVITY_MASTERY.md
  • Main Programming Language: JavaScript
  • Alternative Programming Languages: TypeScript
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 3: Advanced
  • Knowledge Area: Scope / Context Management
  • Software or Tool: Browser
  • Main Book: “Vue.js 3 Design and Implementation” by Huo Chunyang

What you’ll build: A provide(key, value) and inject(key) system that allows components to share data across deep hierarchies without “prop drilling.”

Why it teaches Vue internals: You’ll learn how the component tree is linked together. You’ll understand how Vue uses prototypical inheritance to make data available to an entire branch of the component tree.

Core challenges you’ll face:

  • Parent-Child Linkage → Ensuring every component instance knows who its parent is.
  • Shadowing → If both a parent and a grandparent “provide” the same key, the child should get the parent’s version.
  • Reactivity in Injection → Ensuring that if the provided value is a ref, the injecting component stays reactive to it.

Key Concepts:

  • Component Instance Links: The parent property on instances.
  • The provides Object: How it’s inherited from the parent.
  • Prototypical Inheritance: Using Object.create(parent.provides).

Difficulty: Advanced Time estimate: 2 days Prerequisites: Completion of Project 10 (Component System).


Real World Outcome

You’ll build a way to share a “Theme” or “User Session” across your whole app effortlessly.

Example Output:

const Parent = {
  setup() {
    provide('theme', 'dark');
  },
  render() { return h(Child); }
};

const Child = {
  setup() {
    const theme = inject('theme');
    return { theme };
  },
  render(state) {
    return h('div', { class: state.theme }, 'Current Theme: ' + state.theme);
  }
};

The Core Question You’re Answering

“How can data ‘skip’ layers of components without passing it through every single one?”

Prop drilling makes code brittle. Provide/Inject creates a “context” that flows down the tree. The secret is that each component’s provides object is just a prototype link to its parent’s provides.


Concepts You Must Understand First

Stop and research these before coding:

  1. JavaScript Prototype Chain
    • What happens when you access a property on an object created with Object.create(parent)?
    • How does this naturally handle “shadowing”?
  2. Component Lifecycle Hooks
    • Why must provide and inject be called during setup()?

Questions to Guide Your Design

  1. Storage: Where should the provides data be stored on the component instance?
  2. Inheritance: When a component is created, should it get its own empty provides object, or should it point to its parent’s? (Hint: It should point to the parent’s until it calls provide itself).
  3. Current Instance: How does the inject() function know which component is calling it? (Hint: You’ll need a global currentInstance variable that is set before setup() runs).

Thinking Exercise

The Invisible Bridge

let currentInstance = null;

function provide(key, val) {
  if (!currentInstance) return;
  let provides = currentInstance.provides;
  const parentProvides = currentInstance.parent && currentInstance.parent.provides;
  
  if (provides === parentProvides) {
    // We are providing for the first time in this component
    provides = currentInstance.provides = Object.create(parentProvides);
  }
  provides[key] = val;
}

Questions:

  • Why do we use Object.create(parentProvides)?
  • What happens if we just did provides[key] = val without the prototype link?
  • How does inject find the key if it’s not in the immediate parent?

The Interview Questions They’ll Ask

  1. “How does provide/inject work internally in Vue 3?”
  2. “Why is prototypical inheritance used for the provides object?”
  3. “What happens if a child component provides a key that already exists in a parent?”
  4. “Why can provide/inject only be used inside setup() (or the lifecycle)?”
  5. “Is the data injected by inject() reactive? Why or why not?”

Hints in Layers

Hint 1: The Parent Link When you create a component instance in Project 10, pass the parent instance to it. Store it as instance.parent.

Hint 2: The provides Object Initial state of instance.provides should be instance.parent ? instance.parent.provides : {}.

Hint 3: provide() logic When provide(key, value) is called, check if the current component’s provides is the same object as its parent’s. If it is, it means this component hasn’t provided anything yet. Use Object.create(parent.provides) to give the component its own “shadow” object.

Hint 4: inject() logic inject(key) is simple: it just looks for key in currentInstance.parent.provides. Because of the prototype chain, it will search all the way up to the root!


Books That Will Help

Topic Book Chapter
Dependency Injection “Vue.js 3 Design and Implementation” Ch. 13.5
Prototypal Inheritance “You Don’t Know JS: this & Object Prototypes” Ch. 5

Implementation Hints

To make provide/inject work, you need to maintain a global currentInstance variable. Set it right before calling setup() and set it back to null (or the previous instance) right after. This is the “Context” pattern.


Learning Milestones

  1. Basic injection works → Child can read data from parent.
  2. Shadowing works → Intermediate component can override a parent’s value.
  3. Deep injection works → Grandchild can read data from grandparent.

Project 15: Teleport and Fragments (Built-in Components)

  • File: VUEJS_INTERNALS_REACTIVITY_MASTERY.md
  • Main Programming Language: JavaScript
  • Alternative Programming Languages: TypeScript
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 4: Expert
  • Knowledge Area: DOM Manipulation / Rendering Logic
  • Software or Tool: Browser
  • Main Book: “Vue.js 3 Design and Implementation” by Huo Chunyang

What you’ll build: Implement Teleport (rendering content into a different DOM node) and Fragment (rendering children without a wrapper div).

Why it teaches Vue internals: You’ll learn how to extend the renderer to support “special” VNode types. You’ll understand how Vue maintains the Virtual DOM tree structure even when the physical DOM structure is different.

Core challenges you’ll face:

  • Teleporting → Managing the patch process when the container is not the parent element.
  • Fragment Diffing → Handling multiple “root” nodes and updating them correctly during a patch.
  • Anchors → Using “empty text nodes” or “comment nodes” as placeholders to keep track of where components live in the DOM.

Key Concepts:

  • Built-in Components: “Vue.js 3 Design and Implementation” Ch. 14
  • Teleport Logic: “Vue.js 3 Design and Implementation” Ch. 14.2
  • Fragments: “Vue.js 3 Design and Implementation” Ch. 12.7

Difficulty: Expert Time estimate: 3 days Prerequisites: Completion of Projects 7 and 10.


Real World Outcome

You’ll be able to build Modals and Tooltips that sit at the top level of the HTML, while still being controlled by a child component.

Example Output:

const Modal = {
  render() {
    return h(Teleport, { to: 'body' }, [
      h('div', { class: 'modal' }, 'I am in the body!')
    ]);
  }
};

The Core Question You’re Answering

“How can a component render something ‘outside’ of itself?”

Normally, the DOM follows the component hierarchy. Teleport breaks this rule. The renderer must be smart enough to send the mount and patch operations to a different target node, while still keeping the reactive links tied to the original component.


Concepts You Must Understand First

Stop and research these before coding:

  1. DOM Tree vs Component Tree
    • How can they differ?
    • Why is it useful for accessibility (Modals)?
  2. Anchor Nodes
    • Why do we need a “placeholder” in the original spot where the Teleport was declared?

Questions to Guide Your Design

  1. Special Types: How do you represent Teleport and Fragment as VNode types? (Hint: Use Symbols).
  2. Teleport Target: How do you find the target container? (Hint: document.querySelector(props.to)).
  3. Fragments: If a VNode is a Fragment, its el can’t be a single element. How do you handle patching its children?

Thinking Exercise

The Displaced Child

Imagine you have a list of items inside a Fragment. <> <li>1</li> <li>2</li> </>

Questions:

  • What is the vnode.el for the Fragment?
  • When you want to remove the whole Fragment from the DOM, how do you know which elements to delete?
  • If you use a Teleport, does the setup() of the teleported content still run in the context of the parent component? (Yes!).

The Interview Questions They’ll Ask

  1. “What is a Fragment in Vue 3 and why do we need it?”
  2. “How does the Teleport component work internally?”
  3. “How does Vue handle ‘anchors’ when rendering Fragments?”
  4. “Can you have multiple root nodes in a Vue 3 component? How is this implemented?”
  5. “If a component is teleported to the body, does it still receive props from its parent? How?”

Hints in Layers

Hint 1: Symbols for Types Define const Fragment = Symbol('Fragment') and const Teleport = { __isTeleport: true, process: ... }.

Hint 2: Handling Fragments In patch, if type === Fragment, simply call mountChildren or patchChildren. The container remains the same. Use a placeholder (like an empty text node) to mark the start and end of the fragment.

Hint 3: Teleport Setup In patch, if the type is a Teleport, call the process method on the Teleport object. Pass it the n1, n2, and a container found via document.querySelector(n2.props.to).

Hint 4: Moving Teleports If the to prop changes, the Teleport needs to move all its children from the old container to the new one. This is why keeping the subtree in the VNode is so important!


Books That Will Help

Topic Book Chapter
Teleport & Fragments “Vue.js 3 Design and Implementation” Ch. 14

Implementation Hints

Teleport is unique because it’s a “renderer-aware” component. It needs access to the mount and patch functions of the renderer itself. In your project, you can pass these functions as an “internals” object to the Teleport’s process method.


Learning Milestones

  1. Fragments work → Components can render multiple top-level elements.
  2. Teleport works → Content appears in a different part of the DOM.
  3. Reactive Teleport works → Changing state in the parent updates the teleported content.

Project 16: Custom Renderer API (Vue Everywhere)

  • File: VUEJS_INTERNALS_REACTIVITY_MASTERY.md
  • Main Programming Language: JavaScript
  • Alternative Programming Languages: TypeScript
  • Coolness Level: Level 5: Pure Magic
  • Business Potential: 4. The “Open Core” Infrastructure
  • Difficulty: Level 4: Expert
  • Knowledge Area: Abstraction / Platform Engineering
  • Software or Tool: Canvas API / Terminal (Blessed)
  • Main Book: “Vue.js 3 Design and Implementation” by Huo Chunyang

What you’ll build: Refactor your renderer so it doesn’t use document.createElement directly. Instead, it will use a “nodeOps” object. Then, implement a renderer for the HTML5 Canvas or the Terminal.

Why it teaches Vue internals: You’ll learn how Vue separates “Core Logic” (diffing, reactivity) from “Platform Logic” (DOM, Canvas, Native). This is how tools like NativeScript-Vue or Weex work.

Core challenges you’ll face:

  • Defining the Interface → What are the universal operations needed to build a UI? (createElement, insert, setElementText, etc.).
  • Managing the Host Object → In Canvas, there is no “DOM.” You’ll need to create a JavaScript object tree that mimics the DOM.
  • Render Loop → In Canvas, you need to clear and re-draw the whole frame whenever a “node” changes.

Key Concepts:

  • Renderer Abstraction: “Vue.js 3 Design and Implementation” Ch. 7.1
  • Platform Specific Options: The createRenderer function.

Difficulty: Expert Time estimate: 4-5 days Prerequisites: Completion of Projects 1-10.


Real World Outcome

You’ll be able to build a reactive dashboard that renders entirely to a <canvas> element or even your command line!

Example Output:

const renderer = createRenderer({
  createElement: (tag) => ({ tag, props: {}, children: [] }),
  insert: (child, parent) => { /* Draw to Canvas here */ },
  // ...other ops
});

renderer.render(h('rect', { x: 10, y: 10, width: 100 }), canvasContext);

The Core Question You’re Answering

“Can Vue work without a browser?”

Yes! By abstracting away the DOM, the reactivity system and the diffing algorithm become platform-independent. This project proves that Vue is not a web library; it’s a general-purpose state-to-UI engine.


Concepts You Must Understand First

Stop and research these before coding:

  1. Dependency Inversion Principle
    • How can you write code that doesn’t care about the implementation of its dependencies?
  2. Canvas API (or Terminal UI)
    • How do you draw shapes programmatically?
    • How do you handle “updates” in a non-retained mode system?

Questions to Guide Your Design

  1. The Interface: Look at Vue’s @vue/runtime-dom source. What are the 10-15 functions it passes to the base renderer?
  2. The “Shadow” Tree: If your host platform doesn’t store a tree (like Canvas), how do you store your “elements” so you can diff them?
  3. Event Emulation: How do you handle onClick in a Canvas renderer? (Hint: You’ll need to listen for clicks on the main canvas and calculate which “virtual rect” was hit).

Thinking Exercise

The Universal Engine

Imagine you want to use Vue to control a fleet of Smart Lightbulbs.

Questions:

  • What would createElement do?
  • What would patchProp do for a prop named color?
  • Would the effect system still work the same way? (Yes!).

The Interview Questions They’ll Ask

  1. “What is a ‘Custom Renderer’ in Vue 3?”
  2. “Explain the role of nodeOps in Vue’s architecture.”
  3. “How does Vue’s renderer maintain platform independence?”
  4. “What would you need to implement to make Vue render to a PDF or a Terminal?”
  5. “How does the diffing algorithm change when using a custom renderer? (Hint: It doesn’t!)”

Hints in Layers

Hint 1: The Factory Wrap your renderer from Project 6/7 in a function: function createRenderer(options) { ... }.

Hint 2: Replacing DOM calls Inside createRenderer, replace every call to document.createElement with options.createElement. Replace el.textContent = ... with options.setElementText.

Hint 3: The Canvas Implementation Create a canvasOptions object. createElement returns a JS object with coordinates. insert adds that object to a global array.

Hint 4: The Draw Loop In canvasOptions.patchProp, whenever a property changes, trigger a drawAll() function that clears the canvas and iterates through your “shadow tree” to draw everything.


Books That Will Help

Topic Book Chapter
Custom Renderers “Vue.js 3 Design and Implementation” Ch. 7

Implementation Hints

Focus on the abstraction first. Get your DOM renderer working through the createRenderer interface. Once that works, building the Canvas one is just a matter of writing the drawing logic.


Learning Milestones

  1. Abstraction works → DOM renderer works via the new API.
  2. Custom host works → You can create “nodes” in a non-DOM system.
  3. Reactive custom host works → Changing a reactive variable updates the Canvas/Terminal UI.

Project 17: Reactive Store (Mini Pinia/Vuex)

  • File: VUEJS_INTERNALS_REACTIVITY_MASTERY.md
  • Main Programming Language: JavaScript
  • Alternative Programming Languages: TypeScript
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: 2. The “Micro-SaaS / Pro Tool”
  • Difficulty: Level 2: Intermediate
  • Knowledge Area: State Management / Patterns
  • Software or Tool: Node.js
  • Main Book: “Vue.js 3 Design and Implementation” by Huo Chunyang

What you’ll build: A global state management library using reactive, computed, and Project 14’s provide/inject. It will support “actions,” “getters,” and “state.”

Why it teaches Vue internals: You’ll see that “Store” libraries are just thin wrappers around the reactivity system. You’ll learn how to organize global state in a way that remains performant and debuggable.

Core challenges you’ll face:

  • State Isolation → Ensuring that state can only be modified through defined actions (if you choose to enforce it).
  • Computed Getters → Mapping your store’s computed properties so they only re-run when relevant state changes.
  • SSR Compatibility → Ensuring the store can be “hydrated” with data from the server.

Key Concepts:

  • State Patterns: Singleton vs. Provider.
  • Action Context: Handling this in store actions.

Difficulty: Intermediate Time estimate: 1 day Prerequisites: Completion of Projects 1-5 and 14.


Real World Outcome

You’ll have a fully functional state management library that you could actually use in a production app.

Example Output:

const useCounter = defineStore('counter', {
  state: () => ({ count: 0 }),
  getters: {
    double: (state) => state.count * 2
  },
  actions: {
    increment() { this.count++; }
  }
});

The Core Question You’re Answering

“Why do we need Pinia if we already have reactive()?”

Reactivity is the engine; a Store is the dashboard. While you could just use a global reactive object, Stores provide structure, debugging tools (like DevTools integration), and a standard pattern for large teams to follow.


Concepts You Must Understand First

Stop and research these before coding:

  1. The Singleton Pattern
    • How to ensure only one instance of a store exists per app.
  2. Higher Order Functions
    • How defineStore returns a function (useStore) that components can call.

Questions to Guide Your Design

  1. Storage: Where does the actual reactive state live? (Hint: In a private Map inside your library).
  2. Access: How does useStore() get access to the provide/inject context?
  3. DevTools: (Optional) How would you notify an external tool whenever a “mutation” or “action” happens?

Thinking Exercise

The Reactivity Leak

Imagine you export a plain reactive object from a file. export const state = reactive({ count: 0 });

Questions:

  • What happens in Server-Side Rendering if 100 users share this same object? (They see each other’s data!).
  • How does using provide/inject (which is per-app instance) solve this problem?
  • Why is it better to return a function () => state instead of the state itself?

The Interview Questions They’ll Ask

  1. “What is the difference between Vuex and Pinia?”
  2. “How would you build a simple state management system using Vue 3’s Composition API?”
  3. “Why is it important to use provide/inject for stores in SSR apps?”
  4. “How do ‘getters’ in Pinia leverage Vue’s computed system?”
  5. “Explain how you would implement ‘Plugins’ for your store library.”

Hints in Layers

Hint 1: The defineStore signature It should take an ID and an options object. It returns a function useStore.

Hint 2: Lazy Initialization Inside useStore, check if the state for this ID already exists in a global WeakMap. If not, create it using reactive(options.state()).

Hint 3: Wrapping Getters Loop through the getters object. For each one, create a computed(() => getter(state)).

Hint 4: Actions and this For each action, bind it to the reactive state so that this.count works correctly inside the action.


Books That Will Help

Topic Book Chapter
State Management “Vue.js 3 Design and Implementation” Ch. 4 (Reactivity basics)

Implementation Hints

To make it truly robust, ensure that the state is wrapped in toRefs before being returned to the user. This allows them to destructure the store without losing reactivity.


Learning Milestones

  1. Basic store works → Components can read and update shared state.
  2. Getters work → Derived state updates automatically and is cached.
  3. Actions work → Complex logic is encapsulated within the store.

Project 18: Full-Stack Reactivity (SSR & Hydration)

  • File: VUEJS_INTERNALS_REACTIVITY_MASTERY.md
  • Main Programming Language: JavaScript (Node.js)
  • Alternative Programming Languages: TypeScript
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: 5. The “Industry Disruptor”
  • Difficulty: Level 5: Master
  • Knowledge Area: Server-Side Rendering / Serialization
  • Software or Tool: Node.js / Browser
  • Main Book: “Vue.js 3 Design and Implementation” by Huo Chunyang

What you’ll build: A system that renders your Virtual DOM to a string on the server (Node.js) and then “hydrates” it on the client, turning static HTML back into an interactive Vue app.

Why it teaches Vue internals: You’ll understand the lifecycle of a Vue app from server to client. You’ll learn about “Isomorphic JavaScript” and how the Virtual DOM enables rendering to strings.

Core challenges you’ll face:

  • String Rendering → Writing a different version of the renderer that produces <div>...</div> instead of DOM nodes.
  • Hydration Logic → The hardest part: Matching the client-side VDOM tree to the existing DOM nodes without flickering or recreating them.
  • State Transfer → Passing the reactive state from the server to the client so the UI matches.

Key Concepts:

  • SSR Rendering: “Vue.js 3 Design and Implementation” Ch. 18.1
  • Hydration Algorithm: “Vue.js 3 Design and Implementation” Ch. 18.3
  • Teleport in SSR: Handling displaced content in strings.

Difficulty: Master Time estimate: 1 week Prerequisites: Completion of Projects 1-10.


Real World Outcome

You’ll build a high-performance app that loads instantly (via HTML) but becomes a fully reactive SPA as soon as the JavaScript loads.

Example Output:

// Server (Node)
const html = await renderToString(h(App));
res.send(`<html><body><div id="app">${html}</div></body></html>`);

// Client (Browser)
const vnode = h(App);
hydrate(vnode, document.getElementById('app'));

The Core Question You’re Answering

“How does a framework ‘wake up’ a piece of static HTML and make it interactive?”

Hydration is like surgery. The renderer walks through the HTML nodes and the Virtual DOM nodes simultaneously. Instead of calling createElement, it just “claims” the existing DOM node and attaches event listeners to it. If they don’t match, it’s a “Hydration Error.”


Concepts You Must Understand First

Stop and research these before coding:

  1. Client-Side vs Server-Side Rendering
    • Why do we do SSR? (SEO, LCP, Performance).
    • What are the tradeoffs?
  2. Serialization
    • How do you turn a JavaScript state object into a string that can be placed in a <script> tag?

Questions to Guide Your Design

  1. The String Renderer: How do you handle children in SSR? (Hint: It’s just recursive string concatenation).
  2. Hydration Pointer: As you hydrate, how do you keep track of which DOM node you are currently looking at?
  3. Mismatches: What should your library do if the server says <p>Hello</p> but the client thinks it’s <span>Hello</span>?

Thinking Exercise

The Mirror Puzzle

Server renders: <div><span>1</span></div> Client generates: h('div', null, [h('span', null, '1')])

Questions:

  • How do you connect the vnode for span to the actual <span> element already on the page?
  • If the server rendered a v-if="true" but the client (due to a different timezone) thinks v-if="false", what happens?
  • Why is it important that the setup() function runs on both the server and the client?

The Interview Questions They’ll Ask

  1. “What is Hydration in the context of Vue SSR?”
  2. “Why are ‘Hydration Mismatches’ common and how do you fix them?”
  3. “Explain the process of rendering a Vue component to a string in Node.js.”
  4. “How is the initial state of the app transferred from server to client?”
  5. “Can you use browser-only APIs (like window) in the setup() function of an SSR app? Why or why not?”

Hints in Layers

Hint 1: renderToString This is a separate recursive function. If a node is an element, return <tag props>children</tag>. If it’s a component, call setup(), then render(), then renderToString() on the result.

Hint 2: The Data Script The server must output <script>window.__INITIAL_STATE__ = ${JSON.stringify(state)}</script>. The client uses this to initialize its reactive state.

Hint 3: hydrate basics hydrate is a modified patch. Instead of hostCreateElement, it uses hostNextSibling and hostSetTextContent. It moves through the DOM tree as it moves through the VDOM tree.

Hint 4: Claiming Nodes For each VNode, find the corresponding DOM node. Set vnode.el = domNode. Then, attach event listeners. If it’s a component, create the instance and point it to these existing nodes.


Books That Will Help

Topic Book Chapter
SSR & Hydration “Vue.js 3 Design and Implementation” Ch. 18

Implementation Hints

Start by making sure your renderToString handles the basic h() nodes. Then, tackle the hydrate function. Hydration is notoriously difficult to get right—don’t be afraid to start with a “dirty” version that just checks if types match.


Learning Milestones

  1. renderToString works → You can generate HTML from VNodes on the server.
  2. Basic Hydration works → Static HTML becomes interactive without a full re-render.
  3. State Hydration works → Server-side state is correctly picked up by the client.

Project Comparison Table

Project Difficulty Time Depth of Understanding Fun Factor
1. Reactive Proxy Level 1 2-4h Intermediate ⭐⭐⭐
2. Dependency Tracking Level 3 1 week Deep ⭐⭐⭐⭐
4. Computed Level 3 2 days Deep ⭐⭐⭐
8. List Diffing (LIS) Level 5 1 week Master ⭐⭐⭐⭐⭐
10. Component System Level 4 5 days Deep ⭐⭐⭐⭐
13. Code Gen Level 5 5 days Master ⭐⭐⭐⭐⭐
16. Custom Renderer Level 4 5 days Deep ⭐⭐⭐⭐⭐
18. SSR / Hydration Level 5 1 week Master ⭐⭐⭐⭐

Recommendation

Start with Project 1 & 2. Reactivity is the foundation of everything else. If you don’t understand how a variable “tracks” a function, you’ll struggle with the Virtual DOM and the Compiler. Once you can make a console log appear automatically when a variable changes, the “magic” starts to fade, and the real engineering begins.


Final Overall Project: “The Omniscient Framework”

Build a complete, mini-frontend framework that includes:

  1. Reactivity: Proxies, Refs, and Computed.
  2. Compiler: A CLI tool that takes .myvue files and turns them into JS.
  3. Renderer: A dual-target renderer (DOM and Terminal).
  4. State Management: A built-in store system.
  5. SSR: A Node.js server that pre-renders the app.

Outcome: You will have built a simplified version of the entire Vue.js ecosystem. You’ll be able to explain exactly how every line of code in a professional framework works, from the template you type to the pixel that appears on the screen.


Summary

This learning path covers Vue.js Internals through 18 hands-on projects. Here’s the complete list:

# Project Name Main Language Difficulty Time Estimate
1 Reactive Proxy JavaScript Beginner 2-4h
2 Dependency Tracking JavaScript Advanced 1 week
3 Ref Wrapper JavaScript Intermediate 1 day
4 Computed Properties JavaScript Advanced 2 days
5 Watch / WatchEffect JavaScript Advanced 3 days
6 Simple VDOM JavaScript Intermediate 1 day
7 Patching Algorithm JavaScript Advanced 3 days
8 List Diffing (LIS) JavaScript Master 1 week
9 Scheduler JavaScript Advanced 2 days
10 Component System JavaScript Expert 5 days
11 Template Parser JavaScript Expert 4 days
12 Template Transformer JavaScript Expert 3 days
13 Render Function Gen JavaScript Master 5 days
14 Provide / Inject JavaScript Advanced 2 days
15 Teleport / Fragments JavaScript Expert 3 days
16 Custom Renderer JavaScript Expert 5 days
17 Reactive Store JavaScript Intermediate 1 day
18 SSR / Hydration JavaScript Master 1 week

For beginners: Start with projects #1, #3, #6. Build the surface level wrappers. For intermediate: Focus on #2, #4, #7, #9. Master the core update loop. For advanced: Tackle #8, #10, #13, #18. Build the complex architectural machinery.

Expected Outcomes

After completing these projects, you will:

  • Understand every byte of the Vue.js 3 core codebase.
  • Be able to build a reactive UI library from first principles.
  • Master the use of JavaScript Proxies, Reflect, and prototypical inheritance.
  • Understand how to optimize rendering via compile-time analysis.
  • Be prepared for senior-level system design and architecture interviews.

You’ll have built 18 working projects that demonstrate deep understanding of Vue.js from the ground up.