Server Rendered Components in Under 2kb

Tamb
3 min readSep 5, 2019

--

My company uses Java it’s actually really great. Stop making fun of it. We also use Spring for our MVC framework, it’s also really great. We also use Thymeleaf for our templating engine, it’s great… I guess.

The leads for our projects love using Thymeleaf. They distrust React, Vue, Angular 2+ all because they had a really bad experience with AngularJS, and they also hate returning JSON instead of HTML. I understand where the higher-ups are coming from. Modern SPA development with tons of fetch requests can lead to very buggy code, business logic can slip into public-facing JavaScript, it can be a real pain. Moreover, implementing full server-side rendering with these frameworks requires Nashorn, or spinning up an instance of Node, or some other not sane workflow. Plus with my company we have so much core code for currency conversion, internationalization, business logic that absolutely has to remain on the backend (even templating logic) So, it’s pretty much a big N.O. for client-side rendering.

As a Senior Front-end Dev, I was kinda stuck. I want to stress that I love React. And I desperately wanted to use it on our products. But it just isn’t in the cards for us. We are building webapps the old-school way and I was tasked with building huge apps that rerendered DOM a bunch, with reusable components, without a framework or library.

I ended up using some practices to speed up development and make all of these HTML/Thymleaf fragments “componentized”.

I decided to refine these practices and put all of them into a new ultra-light framework called DOMponent.

Domponent run small (less than 2kb), and it wires up a page-full of components at nearly 60fps. It’s not meant to replace React. It’s not meant to force any JSX or handle any client-side rendering/routing. It’s simply a way to add really powerful features (data-binding, code reuse, declarative HTML, internal component state, props inheritance) to plain old HTML.

I know, we’ve seen this before with backbone and stuff. But the syntax here is way way simpler and there is the added bonus of a focus on components and lifecycle methods. And it creates a common syntax among the app for how to define components and their behavior.

Here’s an example of how it works:

  1. Drop a few data attributes into your existing HTML 💻
<div data-component=”Counter”>
<p data-bind=”state:Counter.count”>0</p>
<button data-action=”click->Counter.increment”>
+1
</button>
<button data-action=”click->Counter.decrement”>
-1
</button>
<div>

2. Write a JavaScript class component 🔌

import { Component } from ‘domponent’;
import './Component.scss';
export default class Counter extends Component{
constructor(el){
super(el);
}

increment(){
this.setState({count: (this.state.count + 1)});
}

decrement(){
this.setState({count: (this.state.count — 1)});
}
}

3. Initialize the App ⚡

import Init from ‘domponent’;
import Counter from ‘./Counter.js’;
const config = {
selector: document.getElementById(‘root’),
components: {
Counter
},
appCreated: callbackFunction
};
new Init(config);

And there you go. You now have access to lifecycle methods, one-way data-binding, DOM references and the like. Use this with your templating engine and HTML fragments and you have a components.

Let’s say we’re using Pug and we make a Counter component, you can nest all Counter resources in a /Counter directory:

|_/Counter
|_Counter.pug
|_Counter.scss
|_Counter.js

Your Pug for component can look like this:

// Counter.pugdiv(data-component="Counter" data-state='{"count": #{count}}').count
p(data-bind="state:Counter.count")
button(data-action="click->Counter.increment") + button(data-action="click->Counter.decrement") -

Then you can include your Counter:

include Counter/Counter.pug

If you include your Counter.scss into your Counter.js and bundle it all with Webpack, Parcel, or Rollup you have a modern approach to server-side components. It’s classic webapp technology, but spiced up a notch with Domponent.

I really hope you check out the ReadMe and the demo site.

Peace and love,

Tamb

--

--