πŸš€ The Future of Server-Rendered Web Components: Enhance vs. Lit vs. WebC 🌐

VivekVivek
4 min read

Web components have been around for a while, but server-side rendering (SSR) of custom elements has always been a tricky subject. With modern frameworks moving towards server-first architectures, the demand for HTML-first, SSR-friendly components has never been higher.

So today, let's break down three popular ways to server-render web components in Node.js using:

βœ” Enhance
βœ” Lit
βœ” WebC

We'll explore how they work, their differences, and which one is best suited for building scalable, high-performance applications.


πŸ’‘ The Big Question: Can You Server-Render Web Components?

Absolutely! Web components have always been renderable on the server. Even without JavaScript, you can output basic custom elements on any backend.

Here's a simple example of an SSR-friendly custom element:

<my-custom-element>
  <my-custom-header><h1>Welcome!</h1></my-custom-header>
  <my-custom-button variant="primary"><button>Click Me</button></my-custom-button>
</my-custom-element>

And the CSS:

my-custom-element {
  display: block;
  background: lightyellow;
  padding: 1rem;
}

my-custom-header {
  display: block;
  padding-bottom: 1rem;
  border-bottom: 1px solid rebeccapurple;
}

my-custom-button[variant="primary"] button {
  background: navy;
  color: white;
}

πŸ”₯ No JavaScript needed. The browser renders it just fine. But… is that enough?

In modern component-driven applications, we need:
βœ… Shadow DOM support
βœ… Declarative server rendering
βœ… Hydration for interactivity

This is where Enhance, Lit, and WebC come in!


⚑ Enhance: The Lightweight Server-First Framework

Enhance is a fullstack framework designed with SSR web components in mind. The best part? It’s a standalone library, meaning you can use it in any Node.js app.

πŸ›  Example Enhance Component

export default function MyElement({ html, state }) {
  const { attrs } = state;
  const { hello = "?", easy = [] } = attrs;

  return html`
    <style>
      :host {
        display: block;
        padding: 0.5rem 1rem;
        border: 3px double orange;
      }
    </style>

    <h2>Hello ${hello}!</h2>
    <p>Easy as ${easy.join(", ")}. <slot></slot></p>
  `;
}

And the server-side rendering code:

import MyElement from "./my-element.js";
import enhance from "@enhance/ssr";

const html = enhance({
  elements: { 'my-element': MyElement },
});

const data = { hello: "world", easy: [1, 2, 3] };

const result = html`
  <my-element hello=${data.hello} easy=${data.easy}>Hello from SSR!</my-element>
`;

console.log(result);

πŸš€ Why Use Enhance?

βœ… Simple & lightweight
βœ… No Shadow DOM by default (great for flexibility)
βœ… 0kb JavaScript philosophy

Enhance is great if you want pure SSR components with easy expansion. However, it lacks built-in isomorphic rendering (components running both on server and client).


πŸ”₯ Lit: The Isomorphic Powerhouse

Lit is a popular web component library that provides both client-side and server-side rendering. Unlike Enhance, Lit uses Shadow DOM by default and works well in isomorphic setups.

πŸ›  Example Lit Component

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

export class MyElement extends LitElement {
  static styles = css`
    :host {
      display: block;
      padding: 0.5rem 1rem;
      border: 3px double orange;
    }
  `;

  static properties = {
    hello: {},
    easy: { type: Array },
  };

  constructor() {
    super();
    this.hello = "?";
    this.easy = [];
  }

  render() {
    return html`
      <h2>Hello ${this.hello}!</h2>
      <p>Easy as ${this.easy.join(", ")}. <slot></slot></p>
    `;
  }
}

customElements.define("my-element", MyElement);

πŸ”„ How to Server-Render Lit Components

import { render } from "@lit-labs/ssr";
import { collectResult } from "@lit-labs/ssr/lib/render-result.js";
import { html } from "lit";
import { MyElement } from "./my-element.js";

const result = await collectResult(render(html`
  <my-element hello="world" easy=${[1, 2, 3]}>Hello from SSR!</my-element>
`));

console.log(result);

πŸš€ Why Use Lit?

βœ… Shadow DOM for encapsulation
βœ… Great for isomorphic apps (client & server run the same code)
βœ… Backed by Google & has a strong ecosystem

However, Lit’s SSR mechanism is still evolving, and using it requires some workarounds.


🌟 WebC: The Future of HTML-First SSR

WebC (Web Components Compiler) is a unique, HTML-based approach to writing server-rendered web components. It was created by Eleventy’s team and is quickly gaining traction.

πŸ›  Example WebC Component

<script webc:setup>
  const join = (input) => input.join(", ");
</script>

<style webc:scoped="my-element">
  :host {
    display: block;
    padding: 0.5rem 1rem;
    border: 3px double orange;
  }
</style>

<h2>Hello <span @text="hello"></span>!</h2>
<p>Easy as <span @text="join(easy)">...</span>. <slot></slot></p>

πŸ–₯ How to Server-Render WebC Components

import { WebC } from "@11ty/webc";

const page = new WebC();

page.defineComponents("./components/*.webc");
page.setInputPath("./page.webc");
page.setBundlerMode(true);

const { html } = await page.compile({
  data: { hello: "world", easy: [1, 2, 3] },
});

console.log(html);

πŸš€ Why Use WebC?

βœ… True HTML-first approach
βœ… No JavaScript required for basic components
βœ… Built for SSR-first workflows

WebC is perfect for Eleventy and other SSR-friendly environments, but it lacks built-in client-side hydration.


πŸ† Which One Should You Use?

FeatureEnhanceLitWebC
Shadow DOM❌ Noβœ… Yes⚠ Optional
SSR Supportβœ… Yesβœ… Yesβœ… Yes
Client Hydrationβœ… Yesβœ… Yes⚠ Limited
HTML-Firstβœ… Yes❌ Noβœ… Yes

My Pick? If you love HTML-first development, WebC is the future. However, if you need isomorphic components, Lit might be a better fit. And for pure SSR setups, Enhance is a solid choice!

What do you think? Would you switch to SSR web components? Let me know in the comments! πŸ’¬πŸš€


Hope you like this breakdown! Stay tuned for more web dev insights. πŸš€βœ¨

20
Subscribe to my newsletter

Read articles from Vivek directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Vivek
Vivek

Curious Full Stack Developer wanting to try hands on ⌨️ new technologies and frameworks. More leaning towards React these days - Next, Blitz, Remix πŸ‘¨πŸ»β€πŸ’»