diff --git a/packages/preact/src/entry-server.tsx b/packages/preact/src/entry-server.tsx index 5eee836..a6fee56 100644 --- a/packages/preact/src/entry-server.tsx +++ b/packages/preact/src/entry-server.tsx @@ -1,12 +1,10 @@ -import { useContext } from "preact/hooks"; import renderToString from "preact-render-to-string"; import type { ComponentType } from "preact"; import type { Context, RouteModule } from "@impalajs/core"; -import { HeadContext } from "./head-context"; +import { HeadContext, HeadManager } from "./head-context"; -function HeadContent() { - const headProvider = useContext(HeadContext); - return <>{...headProvider.getHead()}; +function HeadContent({ headManager }: { headManager: HeadManager }) { + return <>{...headManager.getHead()}; } export async function render( @@ -16,13 +14,22 @@ export async function render( ) { const { default: Page } = await mod(); - const body = renderToString(); + // We create a new head manager for each request to avoid sharing state across routes + const headManager = new HeadManager(); + + // Now on each render, each page will use their own head context instead of default one + const body = renderToString( + + + + ); const modules = bootstrapModules?.map( (m) => `` ); - const headContent = renderToString(); + // We then pass the head manager instance that is specific to this request to SSR + const headContent = renderToString(); return { body, diff --git a/packages/preact/src/head-context.tsx b/packages/preact/src/head-context.tsx index c82f6a6..2691f5b 100644 --- a/packages/preact/src/head-context.tsx +++ b/packages/preact/src/head-context.tsx @@ -1,6 +1,6 @@ import { createContext, VNode } from "preact"; -class HeadProvider { +export class HeadManager { private head: VNode[] = []; private removeTag(tag: string) { @@ -31,6 +31,6 @@ class HeadProvider { } } -const headProvider = new HeadProvider(); +const defaultHeadProvider = new HeadManager(); -export const HeadContext = createContext(headProvider); +export const HeadContext = createContext(defaultHeadProvider); diff --git a/packages/react/src/entry-server.tsx b/packages/react/src/entry-server.tsx index 6280a5a..224d318 100644 --- a/packages/react/src/entry-server.tsx +++ b/packages/react/src/entry-server.tsx @@ -1,8 +1,8 @@ import { renderToPipeableStream, renderToStaticMarkup } from "react-dom/server"; -import { ElementType, useContext } from "react"; +import { ElementType } from "react"; import type { Context, RouteModule } from "@impalajs/core"; import { Writable, WritableOptions } from "node:stream"; -import { HeadContext } from "./head-context"; +import { HeadContext, HeadManager } from "./head-context"; class StringResponse extends Writable { private buffer: string; @@ -30,9 +30,8 @@ class StringResponse extends Writable { } } -function HeadContent() { - const headProvider = useContext(HeadContext); - return <>{...headProvider.getHead()}; +function HeadContent({ headManager }: { headManager: HeadManager }) { + return <>{...headManager.getHead()}; } export async function render( @@ -42,22 +41,32 @@ export async function render( ) { const { default: Page } = await mod(); + // We create a new head manager for each request to avoid sharing state across routes + const headManager = new HeadManager(); + const response = new StringResponse(); - const { pipe } = renderToPipeableStream(, { - bootstrapModules, - bootstrapScriptContent: `window.___CONTEXT=${JSON.stringify(context)};`, - onAllReady() { - pipe(response); - }, - onError(error) { - console.error(error); - }, - }); + const { pipe } = renderToPipeableStream( + // Now on each render, each page will use their own head context instead of default one + ( + + + + ), + { + bootstrapModules, + bootstrapScriptContent: `window.___CONTEXT=${JSON.stringify(context)};`, + onAllReady() { + pipe(response); + }, + onError(error) { + console.error(error); + }, + }); const body = await response.getData(); - const head = renderToStaticMarkup(); + const head = renderToStaticMarkup(); return { body, head }; } diff --git a/packages/react/src/head-context.tsx b/packages/react/src/head-context.tsx index b65d899..8ce7fa5 100644 --- a/packages/react/src/head-context.tsx +++ b/packages/react/src/head-context.tsx @@ -1,6 +1,6 @@ import React, { createContext, ReactElement, ReactNode } from "react"; -class HeadProvider { +export class HeadManager { private head: React.ReactElement[] = []; private removeTag(tag: string) { @@ -31,6 +31,6 @@ class HeadProvider { } } -const headProvider = new HeadProvider(); +const defaultHeadManager = new HeadManager(); -export const HeadContext = createContext(headProvider); +export const HeadContext = createContext(defaultHeadManager);