Site / With Remote and SSR

A static site from the same tree

A static host serves files, so every address must be known at build time. The tree knows its places; only the params come from data:

ts
const listSite = (owners: Effect.Effect<ReadonlyArray<string>>) =>
  Site.targets(AppSite, [
    Site.paths(
      OwnerNode,
      Effect.map(owners, ids => ids.map(ownerId => ({ params: { ownerId } }))),
    ),
  ])

const staticBuild = (
  client: Layer.Layer<RemoteClient>,
  owners: Effect.Effect<ReadonlyArray<string>>,
) =>
  ({
    origin: ORIGIN,
    paths: () =>
      Effect.runPromise(
        Effect.map(listSite(owners), listed =>
          listed.map(target => ({ path: target.url, modified: target.modified })),
        ),
      ),
    config: (path: string) => Effect.runPromise(prepare(path, client)),
    plan,
    files: 'flat',
    sitemap: true,
  }) satisfies SiteModule

Site.targets lists the tree in order. A node without params appears once, and a node with params appears once for each set its Site.paths gives. It refuses a node with params that has no paths, so a page cannot be left out without anyone deciding to. In a real build, owners is a server read: Data.prefetch of a query, as the CMS's listSite does (examples/cms/src/ssr/prerender.ts).

staticBuild is a SiteModule, the shape foldkit-ssr/vite's staticSite plugin evaluates after vite build. generateStaticSite runs the same build without Vite, as the test does. Each page is prepared and rendered exactly as the server above renders it, and the sitemap is written from the same list.