|
3 | 3 | import type { AppManifest, SiteInfo } from "@deco/deco";
|
4 | 4 | import { Deco, type PageData, type PageParams } from "@deco/deco";
|
5 | 5 | import { framework as htmxFramework } from "@deco/deco/htmx";
|
6 |
| -import type { ComponentType } from "preact"; |
| 6 | +import type { ComponentChildren, ComponentType } from "preact"; |
7 | 7 | import framework from "./Bindings.tsx";
|
8 | 8 | import type { Plugin } from "$fresh/server.ts";
|
| 9 | +import { renderToString } from "preact-render-to-string"; |
| 10 | +import { HEAD_CONTEXT } from "$fresh/src/runtime/head.ts"; |
9 | 11 | export type { Plugin } from "$fresh/server.ts";
|
10 | 12 |
|
11 | 13 | export interface PluginRoute {
|
@@ -65,12 +67,41 @@ export const component = ({ data }: PageParams<PageData>) => {
|
65 | 67 | return <data.page.Component {...data.page.props} />;
|
66 | 68 | };
|
67 | 69 |
|
| 70 | +const adaptRenderOptions = ( |
| 71 | + render: (data: unknown) => Promise<Response> | Response, |
| 72 | +) => { |
| 73 | + return (data: PageData) => { |
| 74 | + if (data.page.props.options?.serverSideOnly) { |
| 75 | + const headContextValue: ComponentChildren[] = []; |
| 76 | + // Fill the headContextValue with <Head> from the page. |
| 77 | + let res = renderToString( |
| 78 | + <HEAD_CONTEXT.Provider value={headContextValue}> |
| 79 | + {data.page.Component(data.page.props)} |
| 80 | + </HEAD_CONTEXT.Provider>, |
| 81 | + ); |
| 82 | + // Render <Head> to string and add it to the head of the page. |
| 83 | + const headContent = headContextValue.map((child) => { |
| 84 | + try { |
| 85 | + return renderToString(child); |
| 86 | + } catch (error) { |
| 87 | + console.error("Error rendering to string:", error); |
| 88 | + return null; |
| 89 | + } |
| 90 | + }).filter((content) => content !== null).join(""); |
| 91 | + res = |
| 92 | + `<!DOCTYPE html><html><head><meta charset="utf-8">${headContent}</head>${res}</html>`; |
| 93 | + return new Response(res); |
| 94 | + } |
| 95 | + return render(data); |
| 96 | + }; |
| 97 | +}; |
| 98 | + |
68 | 99 | export function createFreshHandler<M extends AppManifest = AppManifest>(
|
69 | 100 | deco: Deco<M>,
|
70 | 101 | ) {
|
71 | 102 | const h: PluginRoute["handler"] = (req: Request, ctx) => {
|
72 | 103 | return deco.handler(req, {
|
73 |
| - RENDER_FN: ctx.render.bind(ctx), |
| 104 | + RENDER_FN: adaptRenderOptions(ctx.render.bind(ctx)), |
74 | 105 | GLOBALS: ctx.state.global,
|
75 | 106 | });
|
76 | 107 | };
|
|
0 commit comments