📚 New Read the State of Greenwood 2024 →

The fullstack web is here

Greenwood is your workbench for the web, embracing web standards from the ground up to empower your stack from front to back.

View in Stackblitz Get Started
$ npx @greenwood/init@latest my-app
Hybrid Routing html.svg

Greenwood is HTML first by design. Start from just an index.html file or leverage hybrid, file-system based routing to easily achieve static and dynamic pages side-by-side. Single Page Applications (SPA) and pre-rendering also supported.

src/
  pages/
    api/
      search.js       # API route
    index.html        # Static (SSG)
    products.js       # Dynamic (SSR)
    about.md          # markdown also supported
Server Rendering build-ssg.svg

Web Components are not only a great component model, but also a great templating model for generating static HTML. Below is a dynamic page in Greenwood powered by the Custom Elements API and server-rendering an imported custom element.

// src/pages/products.js
import { getProducts } from "../lib/db.js";
import "../components/card.js";

export default class ProductsPage extends HTMLElement {
  async connectedCallback() {
    const products = await getProducts();
    const html = products
      .map((product) => {
        const { title, thumbnail } = product;

        return `
          <app-card
            title="${title}"
            thumbnail="${thumbnail}"
          >
          </app-card>
        `;
      })
      .join("");

    this.innerHTML = `
      <h2>Product Catalog</h2>
      <div>${html}</div>
    `;
  }
}
Web Components web-components.svg

Greenwood makes it possible to author real isomorphic Web Components, using Light or Shadow DOM, re-using that same definition across the client and the server. Combined with Web APIs like Constructable Stylesheets and Import Attributes, Web Components make for a compelling solution as the web's own component model.

// src/components/card.js
import themeSheet from "../styles/theme.css" with { type: "css" };
import cardSheet from "./card.css" with { type: "css" };

export default class Card extends HTMLElement {
  connectedCallback() {
    if (!this.shadowRoot) {
      const thumbnail = this.getAttribute("thumbnail");
      const title = this.getAttribute("title");
      const template = document.createElement("template");

      template.innerHTML = `
        <div>
          <h3>${title}</h3>
          <img src="${thumbnail}" alt="${title}">
        </div>
      `;

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

    this.shadowRoot.adoptedStyleSheets = [themeSheet, cardSheet];
  }
}

customElements.define("app-card", Card);
API Routes json.svg

Need client side data fetching or mutations? Greenwood provides API routes out of the box that are fully invested in web standards like Fetch and FormData. Of course it is all fully compatible with server-rendering Web Components; a perfect companion for HTML over the wire solutions!

// src/pages/api/search.js
import { renderFromHTML } from "wc-compiler";
import { getProducts } from "../lib/db.js";

export async function handler(request) {
  const formData = await request.formData();
  const searchTerm = formData.has("term") ? formData.get("term") : "";
  const products = await getProducts(searchTerm);
  const { html } = await renderFromHTML(
    `
    ${products
      .map((item, idx) => {
        const { title, thumbnail } = item;

        return `
          <app-card
            title="${idx + 1}) ${title}"
            thumbnail="${thumbnail}"
          ></app-card>
        `;
      })
      .join("")}
  `,
    [new URL("../components/card.js", import.meta.url)],
  );

  return new Response(html, {
    headers: new Headers({
      "Content-Type": "text/html",
    }),
  });
}

Build With Friends

Greenwood and Web Components work great with all of your favorite tools in the web ecosystem.

Tilted sphere with longitudinal stripes Web Test Runner Open Props

Why Greenwood?

With the web now reaching an impressive ubiquity of full-stack APIs, Greenwood's vision is to be a thin layer of developer experience on top of the web platform.

Less is More

We believe a tech stack aligned to web standards can benefit from needing fewer dependencies and toolchains, lowered design and decision fatigue, and reduced layers of abstraction. Magic is a zero interest rate phenomenon.

Ship Your Source

We strive to ensure that you can ship exactly the code you wrote and, combined with a fast, unbundled, local development experience, Greenwood will have you shipping in no time. Greenwood aims to externalize the framework.

Build to the Future

Having benefited so much from the web, we feel compelled and motivated to participate in its future growth and community groups, to help fill in the gaps so the web can be an even better platform out of the box for everyone.

Run anywhere the web can run

Greenwood helps you take your application to production by embracing platforms that embrace web standards.

Get started in seconds 🚀

$ npx @greenwood/init@latest my-app
View in Stackblitz Get Started