diff --git a/next/next.config.mjs b/next/next.config.mjs index 42a55de0..149bee74 100644 --- a/next/next.config.mjs +++ b/next/next.config.mjs @@ -56,6 +56,84 @@ const nextConfig = { ]; }, + // More: https://nextjs.org/docs/api-reference/next.config.js/headers + async headers() { + return [ + // Add security headers for each page. + { + // This will match all pages. Examples: "/", "/uk", "/uk/node/1". + source: "/:path*", + headers: [ + { + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection + key: "X-XSS-Protection", + value: "1; mode=block", + }, + { + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security + key: "Strict-Transport-Security", + value: "max-age=63072000; includeSubDomains; preload", + }, + ], + }, + + // Enable caching for all pages, setting a short max-age + // and stale-while-revalidate to allow for quick updates. + { + source: "/:path*", + headers: [ + { + key: "Cache-Control", + value: "max-age=60", + }, + // Set Surrogate-Control header to allow Fastly to cache the page. + // https://www.fastly.com/documentation/guides/concepts/edge-state/cache/stale/#applying-staleness-directives-only-to-fastlys-cache + { + key: "Surrogate-Control", + value: + "max-age=300, stale-while-revalidate=60, stale-if-error=86400", + }, + ], + }, + + // Disable cache for all pages when the "next_drupal_draft_data" cookie is present. + { + source: "/:path*", + has: [{ type: "cookie", key: "next_drupal_draft_data" }], + headers: [ + { + key: "Cache-Control", + value: "private, no-cache, no-store, max-age=0, must-revalidate", + }, + ], + }, + + // Disable cache for requests containing "_rsc" query parameter. + // Caching RSC requests would show JSON response for end user when they visit this cached page. + { + source: "/:path*", + has: [{ type: "query", key: "_rsc" }], + headers: [ + { + key: "Cache-Control", + value: "private, no-cache, no-store, max-age=0, must-revalidate", + }, + ], + }, + + // Disable cache for API endpoint. + { + source: "/api/:path*", + headers: [ + { + key: "Cache-Control", + value: "private, no-cache, no-store, max-age=0, must-revalidate", + }, + ], + }, + ]; + }, + webpack(config) { // Grab the existing rule that handles SVG imports const fileLoaderRule = config.module.rules.find((rule) => diff --git a/next/src/app/[locale]/(dynamic)/[...slug]/page.tsx b/next/src/app/[locale]/(dynamic)/[...slug]/page.tsx index 46e4e9c3..9bd2ae4c 100644 --- a/next/src/app/[locale]/(dynamic)/[...slug]/page.tsx +++ b/next/src/app/[locale]/(dynamic)/[...slug]/page.tsx @@ -8,7 +8,6 @@ import { Node } from "@/components/node"; import { REVALIDATE_LONG } from "@/lib/constants"; import { getNodeByPathQuery } from "@/lib/drupal/get-node"; import { getNodeMetadata } from "@/lib/drupal/get-node-metadata"; -import { getNodeStaticParams } from "@/lib/drupal/get-node-static-params"; import { extractEntityFromRouteQueryResult, extractRedirectFromRouteQueryResult, @@ -27,16 +26,6 @@ export async function generateMetadata({ return metadata; } -// Generates static paths for all node types. -export async function generateStaticParams({ - params: { locale }, -}: NodePageParams) { - // TODO: Add the node types you want to generate static paths in the array below. - const nodeTypes = ["nodePages", "nodeArticles"]; - const params = await getNodeStaticParams(nodeTypes, locale, 10); - return params; -} - // We set the revalidate time to a long period because the content is not expected to change frequently. export const revalidate = REVALIDATE_LONG; diff --git a/next/src/app/[locale]/(static)/all-articles/page.tsx b/next/src/app/[locale]/(static)/all-articles/page.tsx index f0f44550..5d4ae43e 100644 --- a/next/src/app/[locale]/(static)/all-articles/page.tsx +++ b/next/src/app/[locale]/(static)/all-articles/page.tsx @@ -1,7 +1,6 @@ import { Metadata } from "next"; import { getTranslations, setRequestLocale } from "next-intl/server"; -import { REVALIDATE_LONG } from "@/lib/constants"; import { getLatestArticlesItems } from "@/lib/drupal/get-articles"; import ArticlesPagination from "./_components/articles-pagination"; @@ -42,8 +41,6 @@ export async function generateMetadata({ }; } -export const revalidate = REVALIDATE_LONG; - export default async function AllArticlesPage({ params: { locale }, searchParams, diff --git a/next/src/app/[locale]/(static)/dashboard/page.tsx b/next/src/app/[locale]/(static)/dashboard/page.tsx index c47e5006..768befc5 100644 --- a/next/src/app/[locale]/(static)/dashboard/page.tsx +++ b/next/src/app/[locale]/(static)/dashboard/page.tsx @@ -22,6 +22,9 @@ import { import { LinkWithLocale } from "@/i18n/routing"; +export const dynamic = "force-dynamic"; // This page is dynamic because it fetches user-specific data. +export const revalidate = 0; // Disable revalidation for this page, as it fetches user-specific data. + export async function generateMetadata({ params: { locale }, }: { diff --git a/next/src/app/[locale]/(static)/dashboard/webforms/[webformName]/[webformSubmissionUuid]/page.tsx b/next/src/app/[locale]/(static)/dashboard/webforms/[webformName]/[webformSubmissionUuid]/page.tsx index 3d52bea6..cc3055d3 100644 --- a/next/src/app/[locale]/(static)/dashboard/webforms/[webformName]/[webformSubmissionUuid]/page.tsx +++ b/next/src/app/[locale]/(static)/dashboard/webforms/[webformName]/[webformSubmissionUuid]/page.tsx @@ -20,6 +20,9 @@ import { import { LinkWithLocale } from "@/i18n/routing"; +export const dynamic = "force-dynamic"; // This page is dynamic because it fetches user-specific data. +export const revalidate = 0; // Disable revalidation for this page, as it fetches user-specific data. + type DashboardPageParams = { params: { locale: string; diff --git a/next/src/app/[locale]/(static)/page.tsx b/next/src/app/[locale]/(static)/page.tsx index 5335a0e7..18284b31 100644 --- a/next/src/app/[locale]/(static)/page.tsx +++ b/next/src/app/[locale]/(static)/page.tsx @@ -8,7 +8,6 @@ import { ContactForm } from "@/components/forms/contact-form"; import { LogoStrip } from "@/components/logo-strip"; import { Node } from "@/components/node"; import { Separator } from "@/components/ui/separator"; -import { REVALIDATE_LONG } from "@/lib/constants"; import { getArticleTeasers } from "@/lib/drupal/get-article-teasers"; import { getNodeByPathQuery } from "@/lib/drupal/get-node"; import { getNodeMetadata } from "@/lib/drupal/get-node-metadata"; @@ -26,8 +25,6 @@ export async function generateMetadata({ return metadata; } -export const revalidate = REVALIDATE_LONG; - export default async function FrontPage({ params: { locale }, }: FrontpageParams) {