Appendix

Build Output

Greenwood produces a consistent build output that typically mirrors the source directory as it persists all file naming, albeit with hashes included. For static content, this can be used by static hosting sites with no additional configuration, on serverless hosting with our adapters, or self-hosted.

The type of output you may see from Greenwood in the output directory, depending on what features you are using, includes:

Taking this sample project layout:

src/
  api/
    greeting.js
    nested/
      endpoint.js
  pages/
    blog/
      first-post.js
      index.js
    index.js

The build output would look like this, with additional chunks being generated as needed based on any input files.

public/
  api/
    greeting.js
    nested-endpoint.js
  blog-first-post.route.js
  blog-first-post.chunk.[hash].js
  blog-index.route.js
  blog-index.route.chunk.[hash].js
  index.route.js
  index.route.chunk.[hash].js

Compilation

In some of Greenwood's docs, like plugins and server rendering, Greenwood makes available its compilation, which is a representation of the internal build and configuration state:

{
  "context": {},
  "config": {},
  "graph": []
}

Configuration

This is the current configuration state of Greenwood, which is a merger of any settings in the project's greenwood.config.js on top of Greenwood's default configuration settings.

Graph

The graph is an array of all pages in the project, as an array. You can see the Pages Data section under our Content as Data docs for more information on the shape and usage options for this.

Context

The context objects provides access to all the input and output directories Greenwood uses to build the site and resolve workspace files, node_modules, build output directories, and more. This is especially useful to plugins as they often involve processing and manipulating files.

Here are some of the most useful paths available on context, all of which are instances of URL:

DOM Emulation

By default, Greenwood handles server rendering with WCC (Web Components Compiler), which brings with it a minimal DOM Shim that emulates a minimal amount of DOM and Web APIs, most as no-ops for the benefit of making SSR and prerendering a bit more ergonomic for development.

It is fine-tuned for creating Light and Shadow DOM based custom elements. The full list is documented here, with some key features being:

While not all DOM APIs are supported, in general you can still use them and combine their usage with optional chaining for a quick "no-op".

export default class HeroBanner extends HTMLElement {
  clickButton() {
    // ...
  }

  connectedCallback() {
    // ...

    this.shadowRoot.querySelectorAll?.("button").forEach((button) => {
      button.addEventListener("click", () => this.clickButton(button));
    });
  }
}

customElements.define("app-hero", HeroBanner);

You can also customize the renderer using a plugin like our Lit SSR renderer plugin for Lit based projects, or create your own renderer plugin.

SSR Escape Hatch

If you want to opt-out an entire connectedCallback from being run during build or SSR (say a component completely dependent on a live DOM), you can do a typeof check for window.

This can be useful when components are very DOM heavy, like querying the DOM and setting up event handlers:

import sheet from "./copy-to-clipboard.css" with { type: "css" };

const template = document.createElement("template");

export default class CopyToClipboard extends HTMLElement {
  connectedCallback() {
    if (!this.shadowRoot && typeof window !== "undefined") {
      template.innerHTML = `
        <button id="icon" title="Copy to clipboard">Copy to clipboard</button>
      `;

      this.attachShadow({ mode: "open" });
      this.shadowRoot.appendChild(template.content.cloneNode(true));

      this.shadowRoot.adoptedStyleSheets = [sheet];

      this.shadowRoot.getElementById("icon")?.addEventListener("click", () => {
        const contents = this.getAttribute("content") ?? undefined;

        navigator.clipboard.writeText(contents);
        console.log("copying the following contents to your clipboard =>", contents);
      });
    }
  }
}

customElements.define("x-ctc", CopyToClipboard);

Environment Variables

When a command is run through the Greenwood CLI, Greenwood will set an environment variable called process.env.__GWD_COMMAND__ that will be the value of the command run.

It can be one of these three values: