Shim
To get custom elements to work in Node.js, you'll need to polyfill DOM APIs. Luckily, @lit-labs/ssr provides a tool that enables just that.
In the last section, you exported three new JavaScript bundles corresponding to each route of the application (/, /login, and /dashboard). If we're going to import client-side bundles in Node.js to get their exported Declarative Shadow DOM HTML templates, Node.js will attempt to parse the JavaScript in the bundle. Declarative Shadow DOM, along with all custom element specifications, is still a browser-based technology, no way around it. Node.js runs on a server that lacks browser specific DOM specifications. You'll need to provide mocked implementations of the custom elements v1 specification so the components you've coded in this book can be interpreted by the Node.js runtime.
@lit-labs/ssr
, the package you'll use to server-side render the Declarative Shadow DOM HTML templates exports a function
named installWindowOnGlobal
. When executed in Node.js, installWindowOnGlobal
provides coverage for autonomous custom elements portion of the Custom Elements v1 specification, but lacks support for the customized built-ins several components from the @in/ui
package and Background
in the client package rely on. If the application just included autonomous custom elements, we could import installWindowOnGlobal
, call the function
and have complete coverage for running custom element code in Node.js.
The shim is stored in a separate package in the repository named @in/dom-shim
at packages/shim
. In this section, you'll code the shim, build the @in/dom-shim
package, so that in the next section you can import the shim and use it.
In packages/shim/index.ts
import the installWindowOnGlobal
method from @lit-labs/ssr
.
xxxxxxxxxx
import { installWindowOnGlobal } from "@lit-labs/ssr/lib/dom-shim.js";
Since you need to support customized built-ins as well, you'll need to mock portions of custom elements specification. This includes HTMLElement
and several of its class
methods, including attributes
, setAttribute
, removeAttribute
, hasAttribute
, attachShadow
, and getAttribute
. Using code from the @lit-labs/ssr
package, mock the HTMLElement class
so we can run custom elements in the context of Node.js. Starting with the attributes
of a HTMLElement
, create a new WeakMap()
and reusable function
named attributesForElement
that will help mock each of the necessary methods on the HTMLElement class
.
xxxxxxxxxx
const attributes = new WeakMap();
const attributesForElement = (element) => {
let attrs = attributes.get(element);
if (!attrs) {
attributes.set(element, (attrs = new Map()));
}
return attrs;
};
Declare a new class
named Element
, leaving it empty. HTMLElement
actually extends from the Element class
in the browser, so you'll mock that same behavior here, only that Element
doesn't exist in Node.js. Define the HTMLElement class
and establish the first getter named attributes
, which calls the attributesForElement function
you defined earlier and returns an Array
of attribute names and values.
xxxxxxxxxx
class Element {}
class HTMLElement extends Element {
get attributes() {
return Array.from(attributesForElement(this)).map(([name, value]) => ({
name,
value,
}));
}
}
This lesson preview is part of the Fullstack Web Components course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.
Get unlimited access to Fullstack Web Components, plus 70+ \newline books, guides and courses with the \newline Pro subscription.
