Create Your Own Vue.js From Scratch - Part 5 (Bringing it all together)
Tags: vue, javascript
Published: 2020-05-23 12:51:14

If you like this article, chances are you'd like what I tweet as well. If you are curious, have a look at my [Twitter profile](https://twitter.com/_marcba). 🚀

This post is the fifth part of a series called **Create Your Own Vue.js From Scratch**, where I teach you how to create the fundamentals of a reactive framework such as Vue.js. To follow this blog post, I suggest you first read the other parts of the series.

# Roadmap 🚘

1. Introduction (this post)
2. [Virtual DOM basics](https://marc.dev/blog/vue-from-scratch-part-2)
3. [Implementing the virtual DOM & rendering](https://dev.to/_marcba/create-your-own-vue-js-from-scratch-part-2-building-the-vdom-3bp2)
4. [Building reactivity](https://dev.to/_marcba/create-your-own-vue-js-from-scratch-part-3-building-the-reactivity-5162)
5. [Bringing it all together](https://dev.to/_marcba/create-your-own-vue-js-from-scratch-part-5-bringing-it-all-together-4eb3)

# Recap

In the last posts, we [created our own virtual DOM](https://marc.dev/blog/vue-from-scratch-part-3) and [replicated a rudimentary Vue 2 reactivity](https://marc.dev/blog/vue-from-scratch-part-4).

For the virtual DOM, we created an engine that allows us to create virtual nodes, mount/unmount them to/from the actual DOM. The code can be found on [Github](https://gist.github.com/themarcba/2a471e1f0592201fc5036cb40bdbee1f).

For the reactivity, we built a dependency class, which we then use to detect changes in object property changes, we bound using `Object.definePropert()`. The code can be found on [Github](https://gist.github.com/themarcba/618264a12f277f10570c30759c592546).

# Preparation

First, we create a new HTML-file add a `div` with the ID `app`, and `<script>` tag.

Second, we copy the following functions from the VDOM example into the `<script></script>`-tag:

-   `h`
-   `mount`
-   `unmount`
-   `patch`

Third, we copy the following elements from the reactivity example into the `<script>`-tag:

-   `Dep`-class
-   `watchEffect`-function
-   `reactive`-function
-   `activeEffect` variable declaration

# Writing our template

Let's assume we want to create a very simple click-counter like this one:

![mini-vue-click-counter](//images.ctfassets.net/r1crnaxclhxs/79NewCkTOeI76hEPSRuCS4/5afd9804552ed093944f6af7b300a18f/mini-vue-click-counter.gif)

We would need a structure like this:

```html
<div id="app">
    <div id="container">
        <h1>NUMBER_OF_CLICKS</h1>
        <p>clicks</p>
    </div>
</div>
```

The `#app`-div is the mounting point for our application, so we just need to create a template for the `.clickContainer` and it's content. For this, we write a function that returns the template we will render to the DOM later, using the `h`-function from the VDOM:

```javascript
function render(clickCount) {
    return h(
        'div',
        { class: 'container' },
        [h('h1', null, clickCount)],
        h('p', null, 'clicks'),
    )
}
```

# Create our reactive state

In this simple example, we only have one variable, so one property in our reactive state:

```javascript
const state = reactive({
    count: 0,
})
```

# Make our VDOM reactive

We're almost done. What we need to do now is to call the `watchEffect` function, so we can react upon changes in the `state.count` property. There are two scenarios for this:

1. It's the first time our callback function gets called: We need to mount the template to the DOM
2. It's not the first time our callback function gets called: We need to `patch()` the node in the DOM

To differenciate between this, let's create a variable `previousNode`.

```javascript
let previousVnode
watchEffect(() => {
    if (!previousVnode) {
        // No previous node. We must mount it to the DOM
    } else {
        // There is a previous node. We need to patch it (update)
    }
})
```

For the first case, we create a new node with our `render` function and mount it to the DOM:

```javascript
previousVnode = render(String(state.count))
mount(previousVnode, document.getElementById('app'))
```

For the second case, we create a new node and patch it to the `previousNode`. (Compare and see what the differences are).

```javascript
const newVnode = render(String(state.count))
patch(previousVnode, newVnode)
previousVnode = newVnode
```

# Create the click event

Our reactive DOM is now done. It will react to changes to the `state.count` variable. The last thing left for our counter to work is to increment the counter on the click of the `#app` element:

We just add `onclick="state.count++"` to it:

```javascript
<div id="app" onclick="state.count++">
```

And voilà! We have a simple click counter, we built on top of our own reactive library.

Congratulations! 🎉

# Add some style

This of course still looks ugly. To make it a little bit fancier, add a `<style>`-tag to the top of the document and add the following CSS code to it:

```css
* {
    user-select: none;
}
body {
    margin: 0;
    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
#app {
    height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
    background: #41b883;
    color: #ffffff;
}

h1 {
    font-size: 10rem;
    font-weight: 900;
    margin: 0;
}

p {
    margin: 0;
    text-align: center;
    font-weight: 100;
    font-size: 3rem;
}
```

# Summary

This is a very simple example, and could be done with **way** less code in simple JavaScript. However, keep in mind that this series is for educational purposes, so you get an insight to the internals of a frontend framework. It's not meant for you to create your own framework and use it in production. (Of course, you could.)

In this last part (for now), there we learned how to put together our own reactivity with our own virtual DOM to create a rudimentary reactive frontend framework. If you are keen to build more stuff on top of this, go ahead. You'll learn a lot in the process. If you built something, let me know and I'll check it out. Curious if someone uses this to learn stuff.

There might be a bonus coming some day where I build something more advanced with this "framework".

The code of this last part can be found on [Github](https://gist.github.com/themarcba/4975abf6340fd3816172c77d4cb8c3ef) as well.


*Original cover photo by [Joshua Earle](https://unsplash.com/@joshuaearle?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on Unplash, edited by [Marc Backes](https://marc.dev/).*