DEV Community

Cover image for Lit vs Rimmel - OOP vs FRP tagged templates
Dario Mannu
Dario Mannu

Posted on • Edited on

Lit vs Rimmel - OOP vs FRP tagged templates

Lit and Rimmel are some relatively similar libraries as they both make use of tagged templates.

There are some key differences which we're going to explore here

Architecture and Programming Paradigm

Lit is a simple, lightweight library for building web components using JavaScript or TypeScript. It uses a reactive update system where changes in data trigger updates to the DOM. It leverages JavaScript template literals for HTML templating, encapsulated in its html tagged templates.
Rimmel implements the streams-oriented paradigm. This library focuses on using RxJS's Observables, Subjects, and BehaviorSubjects to create and manage UI state and behaviors, all of which naturally lends itself to declarative and predictable code.

Templating and Data Binding

Lit offers a templating syntax with html and css tagged templates with its own set of custom directives for advanced functionality like repeating templates, guarding updates, and managing attributes. It has built-in reactive data binding.

Rimmel utilises a single rml tagged template that remains faithful to the HTML syntax, with a twist that template expressions can also be Promises and Observables and will be bound directly wihout the use of a custom DSL.

Component Model

Each Lit component is a class that extends HTMLElement, allowing the use of lifecycle callbacks and state management features provided by the web component standards.
Rimmel Components are designed as plain functions, including web components, which may appeal to developers looking to do functional programming. This approach can make components easier to test and maintain.

State Management

Lit manages state internally within components or through external libraries. The state handling is less declarative compared to Rimmel but fits well within the object-oriented paradigm.

Rimmel doesn't deal with application state management at all. That aspect is entirely delegated to your application streams, so if you use RxJS, which is the most powerful general-purpose streams library that you can also use for state management despite not even being labelled as a state manager, you can manage even the most advanced state with unmatched ease.

Community and Ecosystem

Lit is backed by Google and has a larger community and ecosystem. This popularity brings more third-party tools, libraries, and plugins that integrate well with it.
Rimmel, as a novel library, and a smaller user base has the ability to grow faster. Its natural integration with RxJS could attract developers looking for advanced streams-oriented solutions.

Performance

Lit adopts various engineering tricks to make updates fast through its virtual DOM. Rimmel, on the other hand, uses no virtual dom and instead it just binds event handlers to streams and the real DOM, which means fine-grained reactivity and updates are among the fastest available.

Use Case Suitability

Both Lit and Rimmel are suitable for a wide range of projects. The former fits more where traditionally-structured OOP approaches are preferred, whilst the latter shows it true power in the functional, point-free paradigm.

Action

Let's compare both with a code example: a little component with two buttons that prints "Hello" when both are clicked.

import { LitElement, html, css } from 'lit';

class HelloButtons extends LitElement {
  static properties = {
    firstClicked: { type: Boolean },
    secondClicked: { type: Boolean },
    showMessage: { type: Boolean }
  };

  constructor() {
    super();
    this.firstClicked = false;
    this.secondClicked = false;
    this.showMessage = false;
  }

  firstButtonClicked() {
    this.firstClicked = true;
    this.checkBothClicked();
  }

  secondButtonClicked() {
    this.secondClicked = true;
    this.checkBothClicked();
  }

  checkBothClicked() {
    if (this.firstClicked && this.secondClicked) {
      this.showMessage = true;
    }
  }

  render() {
    return html`
      <button @click="${this.firstButtonClicked}">Button 1</button>
      <button @click="${this.secondButtonClicked}">Button 2</button>
      <div>${this.showMessage ? 'Hello' : ''}</div>
    `;
  }
}

customElements.define('hello-buttons', HelloButtons);
const element = document.createElement('hello-buttons');
document.body.appendChild(element)
Enter fullscreen mode Exit fullscreen mode

Follwing is the Rimmel example, managing state exclusively as RxJS streams. You may notice how shorter did the code become as a result:

import { BehaviorSubject, zip, take } from 'rxjs';
import { rml } from 'rimmel';

function HelloButtons() {
  const first = new Subject();
  const second = new Subject();

  const msg = zip([first, second]).pipe(
    map(() => 'Hello'),
    take(1)
  );

  return rml`
    <button onclick="${first}">Button 1</button>
    <button onclick="${second}">Button 2</button>
    <div>${msg}</div>
  `;
}

document.body.innerHTML = HelloButtons();
Enter fullscreen mode Exit fullscreen mode

Which programming paradigm do you prefer, or find more promising?
Imperative or Functional? Object-Oriented or Streams-Oriented?
Leave a comment below.

Lastly, if you like what you've seen here please don't forget to leave a Star in Github ⭐ so we can continue evolving it for you!

Learn More

Top comments (3)

Collapse
 
dannyengelman profile image
Danny Engelman • Edited

Problem is many developers discount vanilla JS too soon,
grabbing for "tools" that make work "easier"

But a fool with a tool, is still a fool. Offloading intelligence to a Library or a Compiler

Ask such an "expert" to not use a tool, and they probably fail.

(JSFidlle Result tab loads slow)

Collapse
 
dariomannu profile image
Info Comment hidden by post author - thread only accessible via permalink
Dario Mannu

Fools and tools you say? Let's see, let's examine the situation a bit more closely.

For a start, we may agree there's a bit of boilerplate in the vanilla code: class, extends, HTMLElement, constructor, createElement (3x), innerHTML, super(), attachShadow, mode: "open", append.

So, two things come to my mind now:

  1. Vanilla doesn't come with many architectural and design patterns, so you have to reimplement them every single time and if you do, you've just created another framework.

  2. For a long time I didn't know how to create vanilla web components, so I was a fool. Then I have myself created a JS framework from scratch which makes it easy to create powerful monadic web components, so I'm not a fool, but as I now use this tool every day, I've (happily) forgotten how to create them the vanilla way, so I'm back as the same fool.

Houston, we have a little conundrum here :)

P.S.: an AI reviewed my comment and summarised it egregiously: "is mastery about knowing how to do everything manually, or knowing when to use the right tool?"

What do you say?

Collapse
 
dannyengelman profile image
Info Comment hidden by post author - thread only accessible via permalink
Danny Engelman

You don't drive a Fiat 500 on the F1 track
and you don't drive a F1 race car to the supermarket

For a start, we may agree there's a bit of boilerplate in the vanilla code: class, extends, HTMLElement, constructor, createElement (3x), innerHTML, super(), attachShadow, mode: "open", append.

No we don't agree.
By what reasoning are you rimmel and rxjs commands not boilerplate?

The point is, many developers grab for tools without mastering the basics.
Make your 2 button example code work with N buttons to really show what them tools do.

Some comments have been hidden by the post's author - find out more