- Welcome to the Vue 3
Deep Dive with Evan You. This course is designed to help you learn how Vue is put together so you can more effectively build and scale your Vue applications. Most of this course will
be taught by Evan, however, there are some core concepts
that you need to be familiar with in order to really
understand everything that he's talking about,
from the DOM to virtual DOM, to render functions to the
three modules that make up the Vue core. In this video, I'm going to give you
a bit of an explainer so when Evan starts teaching, everything will be a
little more understandable. We'll start with the basics
and if this seems too simple, just stay tuned, we'll get to the more
advanced stuff in a second. So, first of all, what is the DOM or Document Object Model? This is our browser's interface
to change what is displayed on the screen. So if we load
this HTML into the browser, our browser creates these nodes, which it uses to display our webpage. So this HTML maps to a series
of DOM nodes that we can then manipulate using JavaScript. So to interact with the DOM, we can write JavaScript
that looks like this, retrieve this element. We can change its text
content to "New Heading", which updates the node and
then updates our browser. Webpages can have a lot of DOM nodes, which means DOM trees can
have thousands of nodes. That's why we have frameworks
like Vue to do the heavy lifting for us and make a lot
of these JavaScript calls. However, searching and updating thousands of DOM nodes
can obviously get slow. This is why Vue and other
frameworks like it have something called the virtual DOM. The virtual DOM is a way of
representing the DOM using JavaScript objects. For example, this HTML can also be represented by a virtual
node, which looks like this. As you can see, it's
simply a JavaScript object. Vue knows how to take this virtual node and mount it onto the DOM, which updates what we see in our browser. There's actually another step
in here where Vue creates a render function based on our template, which returns a virtual DOM node. Render functions can
look something like this. When a component changes, the
render function gets rerun, which creates another virtual node. We then send the old V node
and the new V node into Vue to compare the two and make updates in the most efficient
way onto our webpage. An effective way of thinking
about the virtual DOM versus the actual DOM are the blueprints
and the actual building. Let's say I've changed some
data on the 29th floor. I've changed the layout of my furniture and added some kitchen cabinets. There are two ways I can
make these changes. First, I can demolish everything on
the 29th floor and rebuild it from scratch, or I can
create new blueprints, compare the old and the new
blueprints and make updates to do the minimal amount of work. This is kind of how the
virtual Dom works and Vue 3 has become even more efficient at
making these updates quickly, which is something you're going
to learn all about in this course. Vue has three core modules. There's the reactivity
module, the compiler module, and the renderer module. Let's go through them one at a time. Our reactivity module allows
us to create JavaScript reactive objects that can
be watched for changes. When code which uses
these objects are run, they're tracked so they can be run later if the reactive object changes. I just finished creating
an entire course on Vue 3 reactivity, which I
highly recommend you take. If you take it before this
course, things will be a lot more understandable when
we get to the reactive part. Next is the compiler module. This knows how to take HTML templates and compile them into render functions. This can happen in the browser runtime, but more often happens when a
Vue project is built, so that a browser only ever
receives render functions. Finally, the renderer module contains code for three
different phases of rendering out a component onto a webpage. There's the render phase, the mount phase and the patch phase. In the render phase, the
render function is called and it returns a virtual DOM node. In the mount phase, the render takes the virtual
DOM node, and makes DOM JavaScript calls to create a webpage. Lastly, in the patch phase, the renderer takes the old virtual node, the new virtual node,
compares the two, and updates only the parts of the
webpage that have changed using DOM JavaScript calls. There you have it, the
three modules of Vue core. Now let's dive into an example
and look at the execution of a simple component. So here you can see my
simple component and it has a template, and a reactive object which is used inside the template. First, the template compiler changes the HTML into a render function. Then, the reactive objects
are initialized using the reactivity module. Next,
inside the renderer module, we enter the render phase, this invokes the render function, which
references the reactive object. We now watch this reactive
object for changes and the render function returns a virtual DOM node. Next in the mount phase, the mount function is called
using the virtual DOM node to create the webpage. Lastly, if any changes happen
to our reactive object, which is being watched, the renderer invokes the
render function, again, creating a new virtual DOM node, both the new and the old virtual
DOM node get sent in to the patch function, which then makes updates
to our webpage as needed. Okay. With this information, it should be a lot easier to
get through the information that Evan's going to throw at
you in the next few lessons. Hope you enjoy it. - There are some benefits of
having a virtual DOM layer, the most important one is that
it completely decouples your component rendering logic from the actual DOM and makes
it more straightforward to reuse the runtime of a
framework in other environments. For example, Vue allows third
party developers to create customized rendering solutions that targets not just the browser, but also native environments
like iOS and Android. It is also possible to use
the API to create a custom renderer that directly renders
to WebGL instead of DOM nodes. So in Vue 2, we in fact already have
this capability. However, the API we provided in
Vue 2 was not officially documented and required
forking our source code in order to maintain it. So that places a lot of maintenance
burden on the developers developing these custom solutions. In V3, we are making the custom
renderer API a first-class API so developers can directly
pull in Vue runtime core as a dependency, and then leverage the custom renderer API to build their own custom renderer. In fact, we already have early users
reporting that they've successfully built a web GL
renderer using the V3 API. Another important aspect about
virtual DOM is it provides the ability to programmatically
construct, inspect, clone, and manipulate the desired
DOM structure before actually returning it to the rendering engine. And you can do all of this
with the full power of JavaScript. Now, this ability is important
because there will eventually be certain cases in UI programming
where the template syntax will be somewhat limiting and
you just need to have the full flexibility of a proper
programming language to express the underlying logic. Now
such cases is in fact, pretty rare in day-to-day UI development. It happens more often when
you are authoring a library or authoring a UI component suite
that you intend to ship to be used by third-party developers. Let's imagine components like a complex type of head box or
an input box associated with a bunch of tasks. These types of components
typically contain very little markup, but they will contain
a lot of interactive logic. And in those cases, the template syntax sometimes
will actually restrict you from expressing the
underlying logic easier. Or sometimes you will find
yourself putting a lot of logic into the templates, but you also still have a
lot of logic separated in JavaScript, whereas render
function allows you to sort of combine all the logic in one place and you don't typically
don't really need to think too much about the
mark-up in those situations. - So what I'm getting from you is that templates will get you
where you want to go in just writing out the HTML like 99% of the time, but every once in a while, you might want to do something
more programmatically and in that case, you want
to code up a render function. And what does a render function look like? - So a render function
in Vue 2 looks like this. So this is an option in
your component definition. Instead of providing a template option, you can give your component
a render function instead. In Vue two, you will receive the H argument that we talked about earlier directly as an argument
to the render function. And you can use that to create
what we call virtual DOM nodes or V nodes for short. A V node takes the first
argument is the type. So here we have creating a div. The second argument is an object
containing all the data or props on the V node. In V2, the API is a little bit verbose
in the sense that you have to be specific about what type
of binding you're passing to the node. For example, if you
want to bind an attribute, you have to nest it
under the ATTRS object, and if you want to bind an event listener, you have to nest it under on. And the third argument is the
child nodes of this V node. So directly passing the string
is a convenient API for you to say, this node only
contains text children, but it can also be an array
that contains more child nodes. So you can, you can have an array
here and nest it with more nested H calls. Now we changed the API with
the goal of simplifying it in Vue 3. The first note about change is we now have a flat prop structure in the sense when you call
H, the second argument now is always a flat object
and you can directly pass an attribute to it. Here we are just giving it an ID. And event listeners by
convention will start with on. So anything with on would automatically be bound as an event listener. So you don't have to think
about the nesting that much. In most cases, you also don't need to think
about whether this should be bound as an attribute or a DOM property, because Vue will intelligently
figure out the best way to do it for you. We in fact check whether
this key exists on the native DOM node as a property,
and if there is a property, we'll set it as a property.
If it doesn't exist, we'll just set it as an attribute. And it has been working out
well so far in practice. - I know that the original sort of virtual DOM implementation, you took inspiration from other
projects. Is that correct? - Yes. There was a library
called Snabbdom, which Vue 2's Virtual DOM was essentially
forked from that. - Okay. And then Vue 3,
the way you coded it here, is this just improving upon the patterns? - Well, Vue 3 was kind
of a complete rewrite. So pretty much from the ground up, everything is just custom. Obviously there are existing
algorithms or like no diffing cause these are areas that we've seen the community
doing extensive research on. So if this is built upon
knowledge of all these previous implementations, but the code itself is now
written from the ground up. - Wow. And that's all
in TypeScript, right? - Yes. All in TypeScript. - Nice. Another change about the render function API is the H helper is now
globally imported directly from Vue itself. This change mainly comes from
the frustration from some users when in Vue 2, because the H is past here
and in fact this H is special because it's bound to the
current component instance. So when you want to split a
large render function into smaller ones, you actually have to pass this H all the way
through these split functions. So that kind of makes it a bit
difficult to... it's just a little annoyance, but with
a globally imported H, you can import it once and
you can split your render function into as many ones
as you want in the same file without having to think about it. - Oh, I see the render function doesn't have an argument. - Right. Well internally,
it does receive arguments, but that's used only by the
compiler generated code. When users use it directly, they always just grab stuff off of this. So if you use the TypeScript
with a defined component API, you'll get full type
inference on this as well. - Wow.