Hello, I’m Carson.

Weekend nothing to do, ready to find an excellent and not much code library to learn. I finally chose the recently released Petite-Vue for the following reasons:

  • The amount of code is small (only 5.8KB) and the source code is highly modular (compared toReact), easy to read
  • Based on theViteBuild, executeyarn devYou can start debugging the source code
  • There is noVirtual DOM, compile-time scheme, can be used as a readVueThe source code of the bedding
  • The underlying reactive update principle also appliesMobx,SolidJSSuch as the library, a reading of multiple harvests

I decided it was him.

But with weekends so precious, and I haven’t used Vue in 4 years, how can I learn the source code efficiently?

It is best to learn the source code without looking at it.

Next, I’ll use the example of petite-vue to demonstrate the correct posture of the source code.

How fast and how

You can think of petite-vue as a simple Vue that replaces the Vue template with the real DOM.

For example, the following Demo:

<script type="module"> import { createApp } from '.. /src' createApp({count: 0}).mount() </script> <div v-scope> <button @click="count++">add 1</button> <p>{{count}}</p> </div>

Div and its descendents are actual DOM tags, so the page is initialized as follows:

Then execute the following code to initialize petite-vue:

createApp({count: 0}).mount()

Page at this time:

Read the framework source code should not be a start from the entrance function all the way debugging, it is easy to muddle. The right way to do it is to peel one layer at a time like an onion:

So, let’s first look at the call stack for the first-screen render from the Performance panel:

The call stack is generally divided into two parts: the blue box and the red box. First, look at the blue box on the left:

CreateContext and Reactive keywords are used to create a reactive context. As for what reactive means, we don’t know yet.

Then look at the red box on the right:

From the depth of the call stack and the effect of the page rendering, we guess that this part of the work includes:

  • traverseDOM
  • Complete the two-way binding of data and view
  • Initialize Rendering

Next, let’s test the conjecture.

Note that we haven’t looked at a single line of the source code so far

Verify the DOM traversal

Walk and walkChildren are called multiple times in the call stack, and most likely they are the methods that traversal the execution of the work. Let’s make sure.

Type log in the source walk method:

export const walk = (node: Node, ctx: Context): ChildNode | null | void => {
  console.log('walk', node);
  // ...  
}

Excluding the text node corresponding to the newline character “\n “, the printing order is as follows:

walk div
walk <button>add 1</button>
walk "add 1"
walk <p>0</p>
walk "0"

Judging from the print, this is a depth-first traversal (traverse the children if it has children, traverse the siblings if it doesn’t).

Obviously, depth-first traversal is used when petite-vue mounts, and each DOM node that is traversed is processed with respect to context state.

In the Demo, the context contains the state {count: 0} :

createApp({count: 0}).mount()

{{count}}

becomes

0

.

Determine the granularity of two-way binding

Next we need to confirm the scope of the two-way binding, namely:

After triggering the update, how much scope
DOMIt will be re-traversed and executed accordingly
DOMOperate?

After opening Performance, click to trigger the update:

As you can see, there is no walk, walkChildren (or similar traversal), just a single method called ReactiveEffect that updates the DOM.

This means that depth-first traversal at mount establishes a one-to-one correspondence between the state and the method used to update the DOM.

Because the correspondence is established, no additional traversal is required to determine the DOM that needs to be changed.

When the state is updated, you just need to find the method that is associated with updating the DOM.

For example, associate the count state with the following function:

function setCount(value) {
  p.textContent = value;
}

So if you call setCount(count) every time the count changes, you’re going to update the DOM for p.

So, the principle of how petite-vue works consists of two things:

  1. mountIs depth-first traversalDOM, for statefulDOM(e.g.,<p>{{count}}</p>) to establishstatewithMethods to update the DOMOne to one correspondence between
  2. updateWhen find thestateThe correspondingMethods to update the DOMAnd perform

As you can see, you can get a general idea of the workflow without going into the source code.

If you want to take things a step further, such as understanding how relationships are established (involving responsive updates), then you need to drill down into the source code.

The recommended Vue 3 Reactivity course on Vue Mastery updates this knowledge in a responsive way.

conclusion

This article shows you how to read the source code for a complex framework — from the abstract to the concrete.

  1. frommountwithupdateWhen the call stack is deducedOverall workflow
  2. fromOverall workflowThe core knowledge found in – responsive updating

Once you have mastered the overall workflow and responsive updates, you can read the sections that interest you so you don’t get bogged down in a huge amount of code.

You, are you failing school?