Skip to content

Commit

Permalink
Improve rendering of site (#351)
Browse files Browse the repository at this point in the history
- Remove `next-runtime-env` as it prevents static rendering (use context
in `layout.tsx` instead)
- Get rid of `config.ts`
- Simplify block preview and provide site config context in there as
well
- Use separate `layout.tsx` files for block preview and site

Supersedes #350 and
#349

To discuss:
- Move `SiteConfigsProvider.tsx` and `SiteConfigProvider.tsx` to
@comet/cms-site?
- Shall we document the following explanation and if yes - where?

----

**Ways to access the current SiteConfig**
- _Page_
Use `await getSiteConfigForDomain(params.domain)`
- _Component_ (Server Rendering)
Not possible, instead pass the necessary data from the page
- _Component or Block-Preview_ (Client Rendering)
Use the `useSiteConfig()`-hook
  • Loading branch information
fraxachun authored Sep 5, 2024
1 parent 4afc0df commit 61e5a0d
Show file tree
Hide file tree
Showing 11 changed files with 144 additions and 111 deletions.
1 change: 0 additions & 1 deletion .env.site-configs.tpl
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
PRIVATE_SITE_CONFIGS='{{ site://configs/private/local }}'
PUBLIC_SITE_CONFIGS='{{ site://configs/public/local }}'
NEXT_PUBLIC_SITE_CONFIGS=$PUBLIC_SITE_CONFIGS
15 changes: 0 additions & 15 deletions site/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
"cache-manager": "^5.6.1",
"graphql": "^15.0.0",
"next": "^14.2.0",
"next-runtime-env": "^3.2.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-intl": "^6.0.0",
Expand Down
21 changes: 12 additions & 9 deletions site/src/app/layout.tsx → site/src/app/[domain]/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,34 @@
import { SitePreviewProvider } from "@comet/cms-site";
import { GlobalStyle } from "@src/layout/GlobalStyle";
import { getSiteConfig } from "@src/middleware";
import { getSiteConfigForDomain } from "@src/middleware";
import { ResponsiveSpacingStyle } from "@src/util/ResponsiveSpacingStyle";
import { SiteConfigProvider } from "@src/util/SiteConfigProvider";
import StyledComponentsRegistry from "@src/util/StyledComponentsRegistry";
import type { Metadata } from "next";
import { draftMode } from "next/headers";
import { PublicEnvScript } from "next-runtime-env";

export const metadata: Metadata = {
title: "Comet Starter",
};

export default async function RootLayout({
children,
params: { domain },
}: Readonly<{
children: React.ReactNode;
params: { domain: string };
}>) {
const { gtmId } = await getSiteConfig();
const siteConfig = await getSiteConfigForDomain(domain);
const isDraftModeEnabled = draftMode().isEnabled;

return (
<html>
<head>
<PublicEnvScript />
</head>
<head />
<body>
{gtmId && (
{siteConfig.gtmId && (
<noscript>
<iframe
src={`https://www.googletagmanager.com/ns.html?id=${gtmId}`}
src={`https://www.googletagmanager.com/ns.html?id=${siteConfig.gtmId}`}
height="0"
width="0"
style={{ display: "none", visibility: "hidden" }}
Expand All @@ -37,7 +38,9 @@ export default async function RootLayout({
<StyledComponentsRegistry>
<GlobalStyle />
<ResponsiveSpacingStyle />
{draftMode().isEnabled ? <SitePreviewProvider>{children}</SitePreviewProvider> : children}
<SiteConfigProvider siteConfig={siteConfig}>
{isDraftModeEnabled ? <SitePreviewProvider>{children}</SitePreviewProvider> : children}
</SiteConfigProvider>
</StyledComponentsRegistry>
</body>
</html>
Expand Down
79 changes: 79 additions & 0 deletions site/src/app/block-preview/[type]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
"use client";
import { BlockPreviewProvider, IFrameBridgeProvider, useBlockPreviewFetch, useIFrameBridge } from "@comet/cms-site";
import { PageContentBlockData } from "@src/blocks.generated";
import { PageContentBlock } from "@src/documents/pages/blocks/PageContentBlock";
import { StageBlock } from "@src/documents/pages/blocks/StageBlock";
import type { ContentScope, PublicSiteConfig } from "@src/site-configs";
import { graphQLApiUrl } from "@src/util/graphQLClient";
import { recursivelyLoadBlockData } from "@src/util/recursivelyLoadBlockData";
import { SiteConfigProvider } from "@src/util/SiteConfigProvider";
import { createContext, PropsWithChildren, useContext, useEffect, useState } from "react";

const PagePreview: React.FunctionComponent = () => {
const iFrameBridge = useIFrameBridge();

const { fetch, graphQLFetch } = useBlockPreviewFetch(graphQLApiUrl);

const [blockData, setBlockData] = useState<PageContentBlockData>();
useEffect(() => {
async function load() {
if (!iFrameBridge.block) {
setBlockData(undefined);
return;
}
const newData = await recursivelyLoadBlockData({
blockType: "PageContent",
blockData: iFrameBridge.block,
graphQLFetch,
fetch,
});
setBlockData(newData);
}
load();
}, [iFrameBridge.block, fetch, graphQLFetch]);

return <div>{blockData && <PageContentBlock data={blockData} />}</div>;
};

const StagePreview = () => {
const { block: stage } = useIFrameBridge();
return stage ? <StageBlock data={stage} /> : null;
};

const previewComponents = {
page: PagePreview,
stage: StagePreview,
};

const PreviewWrapper = ({ type }: { type: string }) => {
const iFrameBridge = useIFrameBridge();
const siteConfigs = useContext(SiteConfigsContext);
if (!iFrameBridge.contentScope) return;
const contentScope = iFrameBridge.contentScope as ContentScope;
const siteConfig = siteConfigs.find((siteConfig) => siteConfig.scope.domain === contentScope.domain);

const PreviewComponent = previewComponents[type];
return (
<SiteConfigProvider siteConfig={siteConfig}>
<PreviewComponent />
</SiteConfigProvider>
);
};

const SiteConfigsContext = createContext<PublicSiteConfig[]>([]);

export function SiteConfigsProvider({ children, siteConfigs }: PropsWithChildren<{ siteConfigs: PublicSiteConfig[] }>) {
return <SiteConfigsContext.Provider value={siteConfigs}>{children}</SiteConfigsContext.Provider>;
}

const PreviewPage = ({ params }: { params: { type: string } }) => {
return (
<IFrameBridgeProvider>
<BlockPreviewProvider>
<PreviewWrapper type={params.type} />
</BlockPreviewProvider>
</IFrameBridgeProvider>
);
};

export default PreviewPage;
21 changes: 21 additions & 0 deletions site/src/app/block-preview/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { GlobalStyle } from "@src/layout/GlobalStyle";
import { getSiteConfigs } from "@src/middleware";
import { ResponsiveSpacingStyle } from "@src/util/ResponsiveSpacingStyle";
import StyledComponentsRegistry from "@src/util/StyledComponentsRegistry";

import { SiteConfigsProvider } from "./[type]/page";

export default async function BlockPreviewLayout({ children }: { children: React.ReactNode }) {
const siteConfigs = getSiteConfigs();
return (
<html>
<body>
<StyledComponentsRegistry>
<GlobalStyle />
<ResponsiveSpacingStyle />
<SiteConfigsProvider siteConfigs={siteConfigs}>{children}</SiteConfigsProvider>
</StyledComponentsRegistry>
</body>
</html>
);
}
44 changes: 0 additions & 44 deletions site/src/app/block-preview/page/page.tsx

This file was deleted.

18 changes: 0 additions & 18 deletions site/src/app/block-preview/stage/page.tsx

This file was deleted.

22 changes: 0 additions & 22 deletions site/src/config.ts

This file was deleted.

18 changes: 17 additions & 1 deletion site/src/middleware.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
import { previewParams } from "@comet/cms-site";
import { getSiteConfigs } from "@src/config";
import { Rewrite } from "next/dist/lib/load-custom-routes";
import { headers } from "next/headers";
import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";

import { createRedirects } from "./redirects/redirects";
import type { PublicSiteConfig } from "./site-configs";

function getHost(headers: Headers) {
const host = headers.get("x-forwarded-host") ?? headers.get("host");
if (!host) throw new Error("Could not evaluate host");
return host;
}

export function getSiteConfigForDomain(domain: string) {
const siteConfig = getSiteConfigs().find((siteConfig) => siteConfig.scope.domain === domain);
if (!siteConfig) throw new Error(`SiteConfig not found for domain ${domain}`);
return siteConfig;
}

async function getSiteConfigForHost(host: string) {
const sitePreviewParams = await previewParams({ skipDraftModeCheck: true });
if (sitePreviewParams?.scope) {
Expand All @@ -22,6 +28,16 @@ async function getSiteConfigForHost(host: string) {
return getSiteConfigs().find((siteConfig) => siteConfig.domains.main === host || siteConfig.domains.preliminary === host);
}

let siteConfigs: PublicSiteConfig[];
export function getSiteConfigs() {
if (!siteConfigs) {
const json = process.env.PUBLIC_SITE_CONFIGS;
if (!json) throw new Error("process.env.PUBLIC_SITE_CONFIGS must be set.");
siteConfigs = JSON.parse(json) as PublicSiteConfig[];
}
return siteConfigs;
}

// Used for getting SiteConfig in server-components where params is not available (e.g. sitemap, not-found - see https://github.com/vercel/next.js/discussions/43179)
export async function getSiteConfig() {
const host = getHost(headers());
Expand Down
15 changes: 15 additions & 0 deletions site/src/util/SiteConfigProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"use client";

import type { PublicSiteConfig } from "@src/site-configs.d";
import { createContext, PropsWithChildren, useContext } from "react";

export const SiteConfigContext = createContext<PublicSiteConfig | undefined>(undefined);
export const useSiteConfig = () => {
const siteConfig = useContext(SiteConfigContext);
if (!siteConfig) throw new Error("SiteConfig not set in SiteConfigProvider");
return siteConfig;
};

export function SiteConfigProvider({ children, siteConfig }: PropsWithChildren<{ siteConfig?: PublicSiteConfig }>) {
return <SiteConfigContext.Provider value={siteConfig}>{children}</SiteConfigContext.Provider>;
}

0 comments on commit 61e5a0d

Please sign in to comment.