DEV Community

Jay Landrum
Jay Landrum

Posted on

Rolling my own front-end framework pt. 1/?

For a long time I've iterated on my own small front-end framework fueled by ongoing developer gripes with popular libraries. My goal here is to write a series of posts as a retrospective on that work, summarize design goals and document the problems I faced and how I chose to solve them.

Repo link: j-templates

The framework was used to make Qwiqwit, a multi-player web-game I built with my friend, Paul.

Some of the initial goals were:

  • No transpile step besides TypeScript
  • Fully typed in the editor, no bindings in string or .html templates
  • Sensibly reactive, no need to self-manage change detection

My goals were reactions to pitfalls present in early React/Angular development. This was 6+ years ago so a lot of these complaints have been addressed since.

Hello World

import { Component } from 'j-templates'; import { div } from 'j-templates/DOM'; // Create the Component class class HelloWorld extends Component { // Override the Template function Template() { return div({}, () => "Hello world"); } } // Convert the class to an element function const helloWorld = Component.ToFunction("hello-world", null, HelloWorld); // Append a new hello-world element to the page Component.Attach(document.body, helloWorld({})); 
Enter fullscreen mode Exit fullscreen mode

Produces the following markup:

<hello-world> <div>Hello world</div> </hello-world> 
Enter fullscreen mode Exit fullscreen mode

All elements are represented as functions that take a configuration object. The HelloWorld component class is converted to a function using the Component.ToFunction(...) method. Calling one of these function returns a NodeDefinition object which is the framework's virtual representation of the DOM.

Element functions (i.e. div, span, p) take a second parameter to define children. This function can return a string to create a text node or one/many NodeDefinition objects. This is all you need to start building static views.

import { Component } from 'j-templates'; import { div, span, h1, b } from 'j-templates/DOM'; class MessageHeader extends Component { Template() { return h1({}, () => "Incoming Message"); } } const messageHeader = Component.ToFunction("message-header", null, MessageHeader); class HelloWorld extends Component { Template() { return [ messageHeader({}), div({}, () => [ b({}, () => "Message Body: "), span({}, () => "Hello world") ]) ]; } } const helloWorld = Component.ToFunction("hello-world", null, HelloWorld); Component.Attach(document.body, helloWorld({})); 
Enter fullscreen mode Exit fullscreen mode

Produces the following markup:

<hello-world> <message-header><h1>Incoming Message</h1></message-header> <div><b>Message Body: </b><span>Hello world</span></div> </hello-world> 
Enter fullscreen mode Exit fullscreen mode

Give it a shot: Code Sandbox. Next post will describe how to bind to data.

Top comments (0)