Skip to content

Server‐Side Rendering

David Ortner edited this page Jan 21, 2025 · 23 revisions

Simple Example

import { Window } from "happy-dom";

const window = new Window({
	innerWidth: 1024,
	innerHeight: 768,
	url: "http://localhost:8080",
});
const document = window.document;

document.write(`
    <html>
        <head>
             <title>Test page</title>
        </head>
        <body>
            <div class="root"></div>
            <script src="app.js"></script>
        </body>
    </html>
`);

// Waits for async operations such as timers, resource loading and fetch() on the page to complete
// Note that this may get stuck when using intervals or a timer in a loop (see IBrowserSettings for ways to mitigate this)
await window.happyDOM.waitUntilComplete();

// Outputs the rendered result
console.log(window.document.documentElement.outerHTML);

// Cancels all ongoing operations and destroys the Window instance
await window.happyDOM.close();

Web Compontents

Happy DOM supports rendering custom elements (web components) server-side using a new web feature called Declarative Shadow DOM.

import { Window } from "happy-dom";

const window = new Window({
	innerWidth: 1024,
	innerHeight: 768,
	url: "http://localhost:8080",
});
const document = window.document;

document.write(`
<html>
   <head>
      <title>Test page</title>
   </head>

   <body>
      <div>
         <my-custom-element>
            <span>Slotted content</span>
         </my-custom-element>
      </div>
      <script>
         class MyCustomElement extends HTMLElement {
            constructor() {
               super();
               this.attachShadow({ mode: "open", serializable: true });
            }

            connectedCallback() {
               this.shadowRoot.innerHTML = \`
                  <style>
                     :host {
                        display: inline-block;
                        background: red;
                     }
                  </style>
                  <div><slot></slot></div>
               \`;
            }
         } 

         customElements.define("my-custom-element", MyCustomElement);
      </script>
   </body>
</html>
`);

/*
Will output:
<my-custom-element>
    <span>Slotted content</span>
    <template shadowroot="open" shadowrootserializable="">
        <style>
            :host {
                display: inline-block;
                background: red;
            }
        </style>
        <div><slot></slot></div>
    </template>
</my-custom-element>
*/
console.log(
	document.body
		.querySelector("div")
		.getHTML({ serializableShadowRoots: true })
);

Virtual Server

A virtual server makes it possible to simulate an HTTP server that serves files from the local file system.

By using a virtual server, we can, among other things, render the build results of bundlers such as Vite and Webpack.

Read more about virtual server

File structure:
 - {root}
   - build
     - index.html
     - style.css
     - script.js
import { Browser } from "happy-dom";

const browser = new Browser({
   settings: {
      fetch: : {
         virtualServers: [
            {
               url: 'https://localhost:8080',
               directory: "./build"
            }
         ]
      }
   }
});

const page = browser.newPage();

await page.goto("https://localhost:8080");

// Waits for async operations such as timers, resource loading and fetch() on the page to complete
// Note that this may get stuck when using intervals or a timer in a loop (see IBrowserSettings for ways to mitigate this)
await page.waitUntilComplete();

// Outputs the rendered result
console.log(
   page.mainFrame.document.documentElement.getHTML({ serializableShadowRoots: true })
);

// Closes the browser
await browser.close()
Clone this wiki locally