🛠️ Building a Tiny framework

Hey ,

I'm thrilled to help you learn JavaScript. Unfortunately, you've landed on a page where you cannot access with your current purchase.

Please upgrade (use this link) access this content.

I'm super eager to help you learn more!

🛠️ Building a Tiny framework

We are going to learn how to use a framework (like React/Vue) by building one ourselves. This approach gives you two benefits:

  • You get to learn how to use a framework since you understand the principles behind it.
  • You get to see how to use Vanilla JavaScript to build something complex, which will then bolster your confidence in JavaScript going forward

We’re going to build two things together at the same time:

  1. The Framework
  2. A Counter App

The Counter App

The Counter app we’re building contains three parts:

  • The Parent Counter
  • The Child Counter
  • The Total Count

It looks like this:

This app doesn’t make sense for a normal user, but it’s perfect for illustrating what goes behind a framework.

You can find the HTML and CSS for the Counter App in the Starter files.

The Setup

We’re going to call the framework “Tiny” since it’s a small framework that’s not recommended for real-world usage. (You’ll understand why it’s not recommended for real-world usage as you go through the lessons).

We’ll begin by creating a tiny.js file. I like to put this inside a folder called Tiny so it’s separate from the Counter app we’re building.

We can then include Tiny into main.js like this:

// main.js
import Tiny from './Tiny/tiny.js'

Then we need to export Tiny from tiny.js so main.js can use it.

// tiny.js
export default function Tiny () {}

The Initial Render

The first thing a framework needs to do is to allow users to render their components onto the DOM. This means users give us the HTML and we render it into the DOM.

We need two things to do this:

  1. The element to render into
  2. The HTML to render

For the element, we make it easier for users by asking them to pass in a selector.

// main.js
Tiny({
  selector: 'main',
})

We can then find the selector in Tiny with document.querySelector.

// tiny.js
export default function Tiny (options) {
  const element = document.querySelector(options.selector)
}

We also want to give users the option to pass in the actual element if the element is hard to find via a simple querySelector.

We can use the same selector option by checking if the selector is a string. If selector is a string, we know we need to run document.querySelector. Otherwise, we know we’ve been given an element.

// tiny.js
export default function Tiny (options) {
  const element = typeof options.selector === 'string'
    ? document.querySelector(options.selector)
    : options.selector
}

Next we need the HTML to render.

We can pass a template property into the Tiny for the HTML.

// main.js
Tiny({
  selector: 'main',
  template: 'Hello World'
})

We can then render the template by setting the element's innerHTML property.

// tiny.js
export default function Tiny (options) {
  // ...
  function _render () {
    element.innerHTML = options.template
  }

  _render()
}

Although it’s possible to pass a string as the template, we usually don’t do this. It’s better to use a method instead because a method allows users to use other properties that are declared within the component. This feature will become very useful soon.

// main.js
Tiny({
  selector: 'main',
  template () {
    return `I'm being rendered onto ${this.selector}`
  }
})

To support this feature, we need to run the template method in Tiny.js.

// tiny.js
export default function Tiny (options) {
  // ...
  function _render () {
    element.innerHTML = options.template()
  }

  _render()
}

Note: Did you notice this is a callback pattern? 😉. template is a function that’s passed into another function (Tiny) to be executed later.

Rendering the Counter App

You can find the HTML in the Starter files. What we need to do now is to render the entire HTML into the DOM. Here’s the necessary code.

// main.js
Tiny({
  // ...
  template () {
    return `
      <div class="component parent-component flow">
        <h1>Parent Counter</h1>
        <p>Count: 0</p>
        <button>Increase count by 1</button>

        <div class="half">
          <div class="component child-component flow">
            <h2>Child Counter</h2>
            <p>Count: 0</p>
            <button>Increase count by 1</button>
            <button>Increase parent count by 1</button>
          </div>
          <div class="component total-component flow text">
            <h2>Total Count</h2>
            <ul>
              <li>Parent Count: 0</li>
              <li>Child Count: 0</li>
              <li>Total Count: 0</li>
            </ul>
          </div>
        </div>
      </div>`
  }
})

That’s it! You should now see the counter app in the DOM. But this time, it’s rendered entirely with JavaScript.