Lit SSR server usage

This package is part of the Lit Labs family of experimental packages. See the Lit Labs page for guidance on using Labs software in production.

In order to render custom elements in Node, they must first be defined and registered with the global customElements API, which is a browser-only feature. As such, Lit SSR includes a DOM shim that provides the minimal DOM APIs necessary to render Lit on the server. (For a list of emulated APIs, see DOM emulation.)

Lit SSR provides two different ways of rendering custom elements server-side: rendering in the global scope or via VM modules. VM modules utilizes Node's vm.Module API, which enables running code within V8 Virtual Machine contexts. The two methods differ primarily in how the DOM shim is loaded.

When rendering in the global scope, shimmed DOM globals (like window, HTMLElement, customElements, etc.) are added directly to the Node.js global scope. This may cause unintended behaviors for other libraries. For instance, some libraries try to detect the running environment by checking for the presence of window in the global scope. In addition, all render requests also share the same global custom element registry, and any data that might be stored globally.

Rendering with VM modules allows each render request to have its own context with a separate global from the main Node process. DOM emulation is only installed within that context, any custom elements being registered are registered in that context, and any global data is contained within that context. VM modules are an experimental Node feature.

GlobalVM Module
  • Easy to use. Can import component modules directly and call render() with templates.
  • Introduces DOM shim to global scope, potentially causing issues with other libraries.
  • Custom elements are registered in a shared registry across different render requests.
  • Does not introduce DOM shim to the global scope.
  • Isolates contexts across different render requests.
  • Less intuitive usage. Need to write and specify a module file with a function to call.
  • Slower due the module graph needing to be re-evaluated per request.

The render() method takes a renderable value, usually a Lit template result, and returns an iterable of strings that can be streamed or concatenated to a string for a response.

Importing render() from @lit-labs/ssr/lib/render-with-global-dom-shim.js will also install a minimal DOM shim in the global scope necessary for lit and component definitions to be loaded for rendering the components server-side. It must be imported before any lit libraries or component.

Note: Loading the DOM shim globally introduces window into the global space which some libraries might look for in determining whether the code is running in a browser environment. If this becomes an issue, consider using SSR with VM Module instead.

Lit also provide a way to load application code into, and render from, a separate VM context with its own global object.

Note: Using this feature requires Node 14+ and passing the --experimental-vm-modules flag to Node because of its use of experimental VM modules for creating a module-compatible VM context.