diff --git a/build/server-worker.js b/build/server-worker.js
index 2b73b67e5..99abb9674 100644
--- a/build/server-worker.js
+++ b/build/server-worker.js
@@ -28,10 +28,12 @@ if (!indexModulePath) {
try {
/** @type {import("../entry.ssr.js")} */
const indexModule = await import(pathToFileURL(indexModulePath).href);
- const html = await indexModule?.render(reqPath, context, {
- client: compilationStats.find((x) => x.name === "client") || {},
- legacy: compilationStats.find((x) => x.name === "legacy") || {},
- });
+ const html = process.env.FRED_SIMPLE_HTML
+ ? `${await indexModule?.renderSimple(reqPath, context)}`
+ : await indexModule?.render(reqPath, context, {
+ client: compilationStats.find((x) => x.name === "client") || {},
+ legacy: compilationStats.find((x) => x.name === "legacy") || {},
+ });
parentPort?.postMessage({ html });
} catch (error) {
parentPort?.postMessage({ error });
diff --git a/components/doc/server.js b/components/doc/server.js
index e17b3955f..5773cbb7f 100644
--- a/components/doc/server.js
+++ b/components/doc/server.js
@@ -5,8 +5,16 @@ import { ServerComponent } from "../server/index.js";
export class Doc extends ServerComponent {
/**
* @param {import("@fred").Context} context
- */ render(context) {
+ */
+ render(context) {
context.pageTitle = context.doc.pageTitle;
return PageLayout.render(context, ReferenceLayout.render(context));
}
+
+ /**
+ * @param {import("@fred").Context} context
+ */
+ renderSimple(context) {
+ return ReferenceLayout.render(context);
+ }
}
diff --git a/components/outer-layout/server.js b/components/outer-layout/server.js
index 5ee26e72b..3e8ad71f3 100644
--- a/components/outer-layout/server.js
+++ b/components/outer-layout/server.js
@@ -26,6 +26,9 @@ export class OuterLayout extends ServerComponent {
if (!asyncStore) {
throw new Error("asyncLocalStorage missing");
}
+ if ("renderSimple" in asyncStore) {
+ throw new Error("OuterLayout called from renderSimple function");
+ }
const { componentsUsed, componentsWithStylesInHead, compilationStats } =
asyncStore;
diff --git a/components/reference-layout/server.js b/components/reference-layout/server.js
index b7abee5c2..948352258 100644
--- a/components/reference-layout/server.js
+++ b/components/reference-layout/server.js
@@ -44,4 +44,18 @@ export class ReferenceLayout extends ServerComponent {
`;
}
+
+ /**
+ * @param {import("@fred").Context} context
+ */
+ renderSimple(context) {
+ const { doc } = context;
+ const sections =
+ doc.body?.map((section) => ContentSection.render(context, section)) || [];
+
+ return html`
+ ${doc.title}
+ ${BaselineIndicator.render(context)} ${sections}
+ `;
+ }
}
diff --git a/components/server/async-local-storage.js b/components/server/async-local-storage.js
index d9ba4fcd4..db2f1b4ac 100644
--- a/components/server/async-local-storage.js
+++ b/components/server/async-local-storage.js
@@ -1,4 +1,13 @@
import { AsyncLocalStorage } from "node:async_hooks";
-/** @type {AsyncLocalStorage} */
+/**
+ * Store for internal context passed around components.
+ *
+ * Generally only used within the `ServerComponent` class itself,
+ * or very special server components (such as the `OuterLayout`).
+ *
+ * Populated in `entry.ssr.js`.
+ *
+ * @type {AsyncLocalStorage}
+ */
export const asyncLocalStorage = new AsyncLocalStorage();
diff --git a/components/server/index.js b/components/server/index.js
index e6ff8a21c..0addb94cb 100644
--- a/components/server/index.js
+++ b/components/server/index.js
@@ -24,6 +24,13 @@ export class ServerComponent {
if (!asyncStore) {
throw new Error("asyncLocalStorage missing");
}
+
+ const component = new this();
+
+ if ("renderSimple" in asyncStore) {
+ return component.renderSimple(...args);
+ }
+
const { componentsUsed, componentsWithStylesInHead, compilationStats } =
asyncStore;
const componentUsedBefore = componentsUsed.has(this.name);
@@ -35,7 +42,7 @@ export class ServerComponent {
componentsUsed.add("legacy");
}
- let res = new this().render(...args);
+ let res = component.render(...args);
if (!res || res === nothing) {
if (!componentUsedBefore) {
@@ -73,4 +80,12 @@ export class ServerComponent {
render(..._args) {
throw new Error("Must be implemented by subclass");
}
+
+ /**
+ * @param {...any} args
+ * @returns {any}
+ */
+ renderSimple(...args) {
+ return this.render(...args);
+ }
}
diff --git a/components/server/types.d.ts b/components/server/types.d.ts
index 9eebcaddf..95e6c238b 100644
--- a/components/server/types.d.ts
+++ b/components/server/types.d.ts
@@ -1,5 +1,9 @@
-export interface AsyncLocalStorageContents {
- componentsUsed: Set;
- componentsWithStylesInHead: Set;
- compilationStats: import("@fred").CompilationStats;
-}
+export type FredLocalContents =
+ | {
+ componentsUsed: Set;
+ componentsWithStylesInHead: Set;
+ compilationStats: import("@fred").CompilationStats;
+ }
+ | {
+ renderSimple: true;
+ };
diff --git a/entry.ssr.js b/entry.ssr.js
index 2b9e63a0f..b16469ef3 100644
--- a/entry.ssr.js
+++ b/entry.ssr.js
@@ -2,6 +2,8 @@
import { render as r } from "@lit-labs/ssr";
import { collectResult } from "@lit-labs/ssr/lib/render-result.js";
+import { nothing } from "lit";
+
import { Advertising } from "./components/advertising/server.js";
import { BlogIndex } from "./components/blog-index/server.js";
import { BlogPost } from "./components/blog-post/server.js";
@@ -54,7 +56,7 @@ export async function render(path, partialContext, compilationStats) {
...(await addFluent(locale)),
...partialContext,
};
- /** @type {import("./components/server/types.js").AsyncLocalStorageContents} */
+ /** @type {import("./components/server/types.js").FredLocalContents} */
const storageContents = {
componentsUsed: new Set(),
componentsWithStylesInHead: new Set(),
@@ -130,3 +132,33 @@ export async function render(path, partialContext, compilationStats) {
}),
);
}
+
+/**
+ * @param {string} path
+ * @param {import("@fred").PartialContext} partialContext
+ */
+export async function renderSimple(path, partialContext) {
+ const locale = path.split("/")[1] || "en-US";
+ const context = {
+ path,
+ ...(await addFluent(locale)),
+ ...partialContext,
+ };
+ /** @type {import("./components/server/types.js").FredLocalContents} */
+ const storageContents = {
+ renderSimple: true,
+ };
+ return asyncLocalStorage.run(storageContents, () =>
+ runWithContext({ locale }, async () => {
+ const component = await (async () => {
+ switch (context.renderer) {
+ case "Doc":
+ return Doc.render(context);
+ default:
+ return nothing;
+ }
+ })();
+ return await collectResult(r(component));
+ }),
+ );
+}