Server Rendering

Server only

Another use case for server rendered components it to use them solely for rendering content, with no dynamic features needed on the client. In this case there is no need to define and load a client version of the content, so the process detailed in parsing and rendering can be used on their own, with no need for hybrid usage.

However, by default, server rendered components serialize all properties as attributes and add an additional wafer-ssr attribute so that they can be 'rehydrated' on the client - all wasted bytes if the component will never be rehydrated. To prevent this behaviour the serverOnly option can be passed to the component registry on a component by component basis when the elements are rendered:

import WaferServer from "@lamplightdev/wafer/lib/server/wafer.js";
import { parse } from "@lamplightdev/wafer/lib/server/element.js";

class MyExample extends WaferServer {
static get template() {
return 'Hi <span id="firstname"></span>!';
}

static get props() {
return {
firstname: {
type: String,
targets: [
{
selector: "$#firstname",
text: true,
},
],
},
};
}
}

const htmlString = `
<div>
<h1>Greeting</h1>
<my-example firstname="Ada"></my-example>
</div>
`
;

const tree = await parse(htmlString, {
"my-example": {
def: MyExample,
serverOnly: true,
},
});

Then when the component is rendered to a string:

response.send(tree.toString());

the following HTML will be sent and rendered in the browser:

<div>
<h1>Greeting</h1>
<my-example>
<template shadowroot="open"> Hi <span id="firstname">Ada</span>! </template>
</my-example>
</div>

Note that there are no unreflected attributes, nor a wafer-ssr attribute, set on the <my-example> tag.

Declarative Shadow DOM polyfill

For components that are using the Shadow DOM, a small polyfill is needed if rendering server only components on browsers that don't support Declarative Shadow DOM (DSD). This can be as simple as including the following script which upgrades any shadowroot templates in the document:

document.querySelectorAll("template[shadowroot]").forEach((template) => {
const mode = template.getAttribute("shadowroot");
const shadowRoot = template.parentNode.attachShadow({ mode });
shadowRoot.appendChild(template.content);
template.remove();
});

For more information please see the DSD reference article.

Previous: Hybrid Usage