Optimize content fetching and update configurations
Content fetching in the marketing section has been refactored to utilize the Next.js cache, which significantly improves performance. The date format of publishedAt has been updated to be more consistent across files. Code related to CSRF token, fonts, and metadata has been refactored into separate files for easier maintenance and readability.
This commit is contained in:
@@ -36,7 +36,7 @@ export async function generateMetadata({
|
||||
title,
|
||||
description,
|
||||
type: 'article',
|
||||
publishedTime: publishedAt?.toDateString(),
|
||||
publishedTime: publishedAt,
|
||||
url: post.url,
|
||||
images: image
|
||||
? [
|
||||
|
||||
@@ -20,7 +20,7 @@ export const PostHeader: React.FC<{
|
||||
|
||||
<div>
|
||||
<span className={'text-muted-foreground'}>
|
||||
<DateFormatter dateString={publishedAt.toISOString()} />
|
||||
<DateFormatter dateString={publishedAt} />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ export function PostPreview({
|
||||
|
||||
<div className="flex flex-row items-center space-x-2 text-sm">
|
||||
<div className="text-muted-foreground">
|
||||
<DateFormatter dateString={publishedAt.toISOString()} />
|
||||
<DateFormatter dateString={publishedAt} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { unstable_cache as cache } from 'next/dist/server/web/spec-extension/unstable-cache';
|
||||
|
||||
import { createCmsClient } from '@kit/cms';
|
||||
import { If } from '@kit/ui/if';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
@@ -18,15 +20,11 @@ export const generateMetadata = async () => {
|
||||
};
|
||||
};
|
||||
|
||||
async function BlogPage({ searchParams }: { searchParams: { page: string } }) {
|
||||
const { t, resolvedLanguage: language } = await createI18nServerInstance();
|
||||
const cms = await createCmsClient();
|
||||
const getContentItems = cache(
|
||||
async (language: string | undefined, limit: number, offset: number) => {
|
||||
const client = await createCmsClient();
|
||||
|
||||
const page = searchParams.page ? parseInt(searchParams.page) : 0;
|
||||
const limit = 10;
|
||||
const offset = page * limit;
|
||||
|
||||
const { items: posts, total } = await cms.getContentItems({
|
||||
return client.getContentItems({
|
||||
collection: 'posts',
|
||||
limit,
|
||||
offset,
|
||||
@@ -34,6 +32,21 @@ async function BlogPage({ searchParams }: { searchParams: { page: string } }) {
|
||||
sortBy: 'publishedAt',
|
||||
sortDirection: 'desc',
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
async function BlogPage({ searchParams }: { searchParams: { page: string } }) {
|
||||
const { t, resolvedLanguage: language } = await createI18nServerInstance();
|
||||
|
||||
const page = searchParams.page ? parseInt(searchParams.page) : 0;
|
||||
const limit = 10;
|
||||
const offset = page * limit;
|
||||
|
||||
const { total, items: posts } = await getContentItems(
|
||||
language,
|
||||
limit,
|
||||
offset,
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { cache } from 'react';
|
||||
|
||||
import { unstable_cache as cache } from 'next/cache';
|
||||
import { notFound } from 'next/navigation';
|
||||
|
||||
import { ContentRenderer, createCmsClient } from '@kit/cms';
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { unstable_cache as cache } from 'next/cache';
|
||||
|
||||
import { createCmsClient } from '@kit/cms';
|
||||
import { PageBody } from '@kit/ui/page';
|
||||
|
||||
@@ -14,14 +16,18 @@ export const generateMetadata = async () => {
|
||||
};
|
||||
};
|
||||
|
||||
async function DocsPage() {
|
||||
const getContentItems = cache(async (resolvedLanguage: string | undefined) => {
|
||||
const client = await createCmsClient();
|
||||
const { t, resolvedLanguage } = await createI18nServerInstance();
|
||||
|
||||
const { items } = await client.getContentItems({
|
||||
return client.getContentItems({
|
||||
collection: 'documentation',
|
||||
language: resolvedLanguage,
|
||||
});
|
||||
});
|
||||
|
||||
async function DocsPage() {
|
||||
const { t, resolvedLanguage } = await createI18nServerInstance();
|
||||
const { items } = await getContentItems(resolvedLanguage);
|
||||
|
||||
// Filter out any docs that have a parentId, as these are children of other docs
|
||||
const cards = items.filter((item) => !item.parentId);
|
||||
|
||||
@@ -1,32 +1,17 @@
|
||||
import { Urbanist as HeadingFont, Inter as SansFont } from 'next/font/google';
|
||||
import Head from 'next/head';
|
||||
import { cookies, headers } from 'next/headers';
|
||||
import { cookies } from 'next/headers';
|
||||
|
||||
import { Toaster } from '@kit/ui/sonner';
|
||||
import { cn } from '@kit/ui/utils';
|
||||
|
||||
import { CsrfTokenMeta } from '~/components/csrf-token-meta';
|
||||
import { RootProviders } from '~/components/root-providers';
|
||||
import appConfig from '~/config/app.config';
|
||||
import { heading, sans } from '~/lib/fonts';
|
||||
import { createI18nServerInstance } from '~/lib/i18n/i18n.server';
|
||||
import { rootMetadata } from '~/lib/root-metdata';
|
||||
|
||||
import '../styles/globals.css';
|
||||
|
||||
const sans = SansFont({
|
||||
subsets: ['latin'],
|
||||
variable: '--font-sans',
|
||||
fallback: ['system-ui', 'Helvetica Neue', 'Helvetica', 'Arial'],
|
||||
preload: true,
|
||||
weight: ['300', '400', '500', '600', '700'],
|
||||
});
|
||||
|
||||
const heading = HeadingFont({
|
||||
subsets: ['latin'],
|
||||
variable: '--font-heading',
|
||||
fallback: ['system-ui', 'Helvetica Neue', 'Helvetica', 'Arial'],
|
||||
preload: true,
|
||||
weight: ['500', '700'],
|
||||
});
|
||||
|
||||
export default async function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
@@ -34,9 +19,10 @@ export default async function RootLayout({
|
||||
}) {
|
||||
const { language } = await createI18nServerInstance();
|
||||
const theme = getTheme();
|
||||
const className = getClassName(theme);
|
||||
|
||||
return (
|
||||
<html lang={language} className={getClassName(theme)}>
|
||||
<html lang={language} className={className}>
|
||||
<Head>
|
||||
<CsrfTokenMeta />
|
||||
</Head>
|
||||
@@ -71,33 +57,4 @@ function getTheme() {
|
||||
return cookies().get('theme')?.value;
|
||||
}
|
||||
|
||||
export const metadata = {
|
||||
title: appConfig.name,
|
||||
description: appConfig.description,
|
||||
metadataBase: new URL(appConfig.url),
|
||||
openGraph: {
|
||||
url: appConfig.url,
|
||||
siteName: appConfig.name,
|
||||
description: appConfig.description,
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
title: appConfig.title,
|
||||
description: appConfig.description,
|
||||
},
|
||||
icons: {
|
||||
icon: '/images/favicon/favicon.ico',
|
||||
shortcut: '/shortcut-icon.png',
|
||||
apple: '/images/favicon/apple-touch-icon.png',
|
||||
other: {
|
||||
rel: 'apple-touch-icon-precomposed',
|
||||
url: '/apple-touch-icon-precomposed.png',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
function CsrfTokenMeta() {
|
||||
const csrf = headers().get('x-csrf-token') ?? '';
|
||||
|
||||
return <meta content={csrf} name="csrf-token" />;
|
||||
}
|
||||
export const metadata = rootMetadata;
|
||||
|
||||
12
apps/web/components/csrf-token-meta.tsx
Normal file
12
apps/web/components/csrf-token-meta.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import { headers } from 'next/headers';
|
||||
|
||||
/**
|
||||
* @description This component is used to render the CSRF token as a meta tag.
|
||||
* this tag can be retrieved for use in forms that require CSRF protection.
|
||||
* @constructor
|
||||
*/
|
||||
export function CsrfTokenMeta() {
|
||||
const csrf = headers().get('x-csrf-token') ?? '';
|
||||
|
||||
return <meta content={csrf} name="csrf-token" />;
|
||||
}
|
||||
30
apps/web/lib/fonts.ts
Normal file
30
apps/web/lib/fonts.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { Urbanist as HeadingFont, Inter as SansFont } from 'next/font/google';
|
||||
|
||||
/**
|
||||
* @sans
|
||||
* @description Define here the sans font.
|
||||
* By default, it uses the Inter font from Google Fonts.
|
||||
*/
|
||||
const sans = SansFont({
|
||||
subsets: ['latin'],
|
||||
variable: '--font-sans',
|
||||
fallback: ['system-ui', 'Helvetica Neue', 'Helvetica', 'Arial'],
|
||||
preload: true,
|
||||
weight: ['300', '400', '500', '600', '700'],
|
||||
});
|
||||
|
||||
/**
|
||||
* @heading
|
||||
* @description Define here the heading font.
|
||||
* By default, it uses the Urbanist font from Google Fonts.
|
||||
*/
|
||||
const heading = HeadingFont({
|
||||
subsets: ['latin'],
|
||||
variable: '--font-heading',
|
||||
fallback: ['system-ui', 'Helvetica Neue', 'Helvetica', 'Arial'],
|
||||
preload: true,
|
||||
weight: ['500', '700'],
|
||||
});
|
||||
|
||||
// we export these fonts into the root layout
|
||||
export { sans, heading };
|
||||
32
apps/web/lib/root-metdata.ts
Normal file
32
apps/web/lib/root-metdata.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { Metadata } from 'next';
|
||||
|
||||
import appConfig from '~/config/app.config';
|
||||
|
||||
/**
|
||||
* @name rootMetadata
|
||||
* @description Define the root metadata for the application.
|
||||
*/
|
||||
export const rootMetadata: Metadata = {
|
||||
title: appConfig.name,
|
||||
description: appConfig.description,
|
||||
metadataBase: new URL(appConfig.url),
|
||||
openGraph: {
|
||||
url: appConfig.url,
|
||||
siteName: appConfig.name,
|
||||
description: appConfig.description,
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
title: appConfig.title,
|
||||
description: appConfig.description,
|
||||
},
|
||||
icons: {
|
||||
icon: '/images/favicon/favicon.ico',
|
||||
shortcut: '/shortcut-icon.png',
|
||||
apple: '/images/favicon/apple-touch-icon.png',
|
||||
other: {
|
||||
rel: 'apple-touch-icon-precomposed',
|
||||
url: '/apple-touch-icon-precomposed.png',
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -6,7 +6,7 @@ export namespace Cms {
|
||||
url: string;
|
||||
description: string | undefined;
|
||||
content: unknown;
|
||||
publishedAt: Date;
|
||||
publishedAt: string;
|
||||
image: string | undefined;
|
||||
slug: string;
|
||||
categories: Category[];
|
||||
|
||||
@@ -16,8 +16,6 @@ export class KeystaticClient implements CmsClient {
|
||||
|
||||
const docs = await reader.collections[collection].all();
|
||||
|
||||
console.log(docs);
|
||||
|
||||
const startOffset = options?.offset ?? 0;
|
||||
const endOffset = startOffset + (options?.limit ?? 10);
|
||||
|
||||
@@ -144,7 +142,7 @@ export class KeystaticClient implements CmsClient {
|
||||
url: item.slug,
|
||||
slug: item.slug,
|
||||
description: item.entry.description,
|
||||
publishedAt,
|
||||
publishedAt: publishedAt.toISOString(),
|
||||
content,
|
||||
image: item.entry.image ?? undefined,
|
||||
categories:
|
||||
|
||||
Reference in New Issue
Block a user