Server Side Rendering

Server side rendering refers to running component code on the server (or during build time) first, instead of running them on the client. This is useful as clients don't have to wait for component code to load and run before seeing their content.

pree pre-renders ALL web components, whether they support SSR or not. Components without interactivity (static components), can be loaded build-only, so that clients don't have to load or execute their code at all. For interactive components, there are two alternatives:

🦕 They can re-render on the client, replacing pre-rendered content, or, 🧠 They can use the pre-rendered content and add interactivity to it.

Naturally, components supporting SSR and hydrating pre-rendered content instead of recreating it, will provide a better performance and user experience as they become interactive faster.


To write components supporting SSR, you can use libraries such as minicomp, combined with rehtm:

import { define } from 'https://esm.sh/minicomp'
import { ref, template } from 'https://esm.sh/rehtm'

define('a-button', () => {
  const span = ref()
  let count = 0
  
  return template`
    <button onclick=${() => span.current.textContent = ++count}>
      Clicked <span ref=${span} role="status">0</span> times
    </button>
  `
})

You can also support SSR without any library, simply check for existence of this.shadowRoot and render accordingly:

class AButton extends HTMLElement {
  constructor() {
    super()

    let span, button
    if (this.shadowRoot) {
      span = this.shadowRoot.querySelector('span')
      button = this.shadowRoot.querySelector('button')
    } else {
      const shadow = this.attachShadow({ mode: 'open' })
      
      span = document.createElement('span')
      span.textContent = 0

      button = document.createElement('button')
      button.append('Clicked ', span, ' times')

      shadow.append(button)
    }

    button.addEventListener('click', () => {
      span.textContent = ++count
    })
  }
}

customElements.define('a-button', AButton)

📖

Read this for more info on hydration with declarative shadow DOM.



pree logo