From 44332242e8250bf774d5283e426694a1d9cc2a83 Mon Sep 17 00:00:00 2001 From: Jon Kafton <939376+jonkafton@users.noreply.github.com> Date: Wed, 16 Oct 2024 19:02:44 +0200 Subject: [PATCH 1/6] Middleware to set cache headers --- frontends/main/src/middleware.ts | 47 ++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 frontends/main/src/middleware.ts diff --git a/frontends/main/src/middleware.ts b/frontends/main/src/middleware.ts new file mode 100644 index 0000000000..e5aff7454c --- /dev/null +++ b/frontends/main/src/middleware.ts @@ -0,0 +1,47 @@ +import { NextResponse } from "next/server" +import type { NextRequest } from "next/server" + +export function middleware(_request: NextRequest) { + const response = NextResponse.next() + response.headers.set("Cache-Control", "public, max-age=120") + + return response +} + +export const config = { + /* The middleware matches on everything by default (all static files, js chunks, + * RSC payloads, etc.). It's safest to list out the paths here, although that does + * leave us with the maintenance overhead. + */ + matcher: [ + /* HTML responses. These are dynamically rendered, so Next.js instructs no-cache, + * however we are currently serving public content that is cacheable. */ + "/", + "/about", + "/c", + "/c/[channelType]", + "/c/[channelType]/[name]", + "/cart", + "/dashboard", + "/dashboard/[tab]", + "/dashboard/[tab]/[id]", + "/departments", + "/learningpaths", + "/learningpaths/[id]", + "/onboarding", + "/privacy", + "/program_letter", + "/program_letter/[id]", + "/program_letter/[id]/view", + "/search", + "/terms", + "/topics", + "/unit", + + /* Images rendered with the Next.js Image component have cache header set for them, + * but CSS background images do not. + */ + "/images/(.*)", + "favicon.ico", + ], +} From 2d3132e8d3632c5dda107cde7eff47c935acf595 Mon Sep 17 00:00:00 2001 From: Jon Kafton <939376+jonkafton@users.noreply.github.com> Date: Wed, 16 Oct 2024 19:21:41 +0200 Subject: [PATCH 2/6] Set headers in the config --- frontends/main/next.config.js | 218 +++++++++++++++++++++++++++++++ frontends/main/src/middleware.ts | 6 +- 2 files changed, 221 insertions(+), 3 deletions(-) diff --git a/frontends/main/next.config.js b/frontends/main/next.config.js index 11658fe0cc..688cc5d825 100644 --- a/frontends/main/next.config.js +++ b/frontends/main/next.config.js @@ -57,6 +57,224 @@ const nextConfig = { ] }, + async headers() { + return [ + /* HTML responses. These are dynamically rendered, so Next.js instructs no-cache, + * however we are currently serving public content that is cacheable. */ + { + source: "/", + headers: [ + { + key: "Cache-Control", + value: "public, max-age=120", + }, + ], + }, + { + source: "/about", + headers: [ + { + key: "Cache-Control", + value: "public, max-age=120", + }, + ], + }, + { + source: "/c", + headers: [ + { + key: "Cache-Control", + value: "public, max-age=120", + }, + ], + }, + { + source: "/c/[channelType]", + headers: [ + { + key: "Cache-Control", + value: "public, max-age=120", + }, + ], + }, + { + source: "/c/[channelType]/[name]", + headers: [ + { + key: "Cache-Control", + value: "public, max-age=120", + }, + ], + }, + { + source: "/cart", + headers: [ + { + key: "Cache-Control", + value: "public, max-age=120", + }, + ], + }, + { + source: "/dashboard", + headers: [ + { + key: "Cache-Control", + value: "public, max-age=120", + }, + ], + }, + { + source: "/dashboard/[tab]", + headers: [ + { + key: "Cache-Control", + value: "public, max-age=120", + }, + ], + }, + { + source: "/dashboard/[tab]/[id]", + headers: [ + { + key: "Cache-Control", + value: "public, max-age=120", + }, + ], + }, + { + source: "/departments", + headers: [ + { + key: "Cache-Control", + value: "public, max-age=120", + }, + ], + }, + { + source: "/learningpaths", + headers: [ + { + key: "Cache-Control", + value: "public, max-age=120", + }, + ], + }, + { + source: "/learningpaths/[id]", + headers: [ + { + key: "Cache-Control", + value: "public, max-age=120", + }, + ], + }, + { + source: "/onboarding", + headers: [ + { + key: "Cache-Control", + value: "public, max-age=120", + }, + ], + }, + { + source: "/privacy", + headers: [ + { + key: "Cache-Control", + value: "public, max-age=120", + }, + ], + }, + { + source: "/program_letter", + headers: [ + { + key: "Cache-Control", + value: "public, max-age=120", + }, + ], + }, + { + source: "/program_letter/[id]", + headers: [ + { + key: "Cache-Control", + value: "public, max-age=120", + }, + ], + }, + { + source: "/program_letter/[id]/view", + headers: [ + { + key: "Cache-Control", + value: "public, max-age=120", + }, + ], + }, + { + source: "/search", + headers: [ + { + key: "Cache-Control", + value: "public, max-age=120", + }, + ], + }, + { + source: "/terms", + headers: [ + { + key: "Cache-Control", + value: "public, max-age=120", + }, + ], + }, + { + source: "/topics", + headers: [ + { + key: "Cache-Control", + value: "public, max-age=120", + }, + ], + }, + { + source: "/unit", + headers: [ + { + key: "Cache-Control", + value: "public, max-age=120", + }, + ], + }, + + /* Images rendered with the Next.js Image component have the cache header + * set on them, but CSS background images do not. + */ + { + source: "/images/(.*)", + headers: [ + { + key: "Cache-Control", + value: "public, max-age=600", + }, + ], + }, + { + source: "/favicon.ico", + headers: [ + { + key: "Cache-Control", + value: "public, max-age=31536000", + }, + ], + }, + ] + }, + images: { remotePatterns: [ { diff --git a/frontends/main/src/middleware.ts b/frontends/main/src/middleware.ts index e5aff7454c..b9238eb791 100644 --- a/frontends/main/src/middleware.ts +++ b/frontends/main/src/middleware.ts @@ -38,10 +38,10 @@ export const config = { "/topics", "/unit", - /* Images rendered with the Next.js Image component have cache header set for them, - * but CSS background images do not. + /* Images rendered with the Next.js Image component have the cache header + * set on them, but CSS background images do not. */ "/images/(.*)", - "favicon.ico", + "/favicon.ico", ], } From edafe9887229f82fea24fc11778952f9d0f83610 Mon Sep 17 00:00:00 2001 From: Jon Kafton <939376+jonkafton@users.noreply.github.com> Date: Wed, 16 Oct 2024 19:25:17 +0200 Subject: [PATCH 3/6] Upgrade Next.js --- frontends/main/package.json | 2 +- yarn.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frontends/main/package.json b/frontends/main/package.json index 063694aba1..bf9db484e3 100644 --- a/frontends/main/package.json +++ b/frontends/main/package.json @@ -18,7 +18,7 @@ "api": "workspace:*", "formik": "^2.4.6", "lodash": "^4.17.21", - "next": "^14.2.7", + "next": "^14.2.15", "ol-ckeditor": "0.0.0", "ol-components": "0.0.0", "ol-utilities": "0.0.0", diff --git a/yarn.lock b/yarn.lock index d467ecc53b..59eafe4da4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13690,7 +13690,7 @@ __metadata: jest: "npm:^29.7.0" jest-extended: "npm:^4.0.2" lodash: "npm:^4.17.21" - next: "npm:^14.2.7" + next: "npm:^14.2.15" ol-ckeditor: "npm:0.0.0" ol-components: "npm:0.0.0" ol-test-utilities: "npm:0.0.0" @@ -15143,7 +15143,7 @@ __metadata: languageName: node linkType: hard -"next@npm:^14.2.7": +"next@npm:^14.2.15, next@npm:^14.2.7": version: 14.2.15 resolution: "next@npm:14.2.15" dependencies: From 27576054a22f7dfb2620951fbfc0a9be6b40cd45 Mon Sep 17 00:00:00 2001 From: Jon Kafton <939376+jonkafton@users.noreply.github.com> Date: Wed, 16 Oct 2024 21:13:47 +0200 Subject: [PATCH 4/6] Regex to exclude paths with a file extension to apply only to routes --- frontends/main/next.config.js | 189 ++-------------------------------- 1 file changed, 6 insertions(+), 183 deletions(-) diff --git a/frontends/main/next.config.js b/frontends/main/next.config.js index 688cc5d825..c7943dda11 100644 --- a/frontends/main/next.config.js +++ b/frontends/main/next.config.js @@ -59,190 +59,13 @@ const nextConfig = { async headers() { return [ - /* HTML responses. These are dynamically rendered, so Next.js instructs no-cache, - * however we are currently serving public content that is cacheable. */ - { - source: "/", - headers: [ - { - key: "Cache-Control", - value: "public, max-age=120", - }, - ], - }, - { - source: "/about", - headers: [ - { - key: "Cache-Control", - value: "public, max-age=120", - }, - ], - }, - { - source: "/c", - headers: [ - { - key: "Cache-Control", - value: "public, max-age=120", - }, - ], - }, - { - source: "/c/[channelType]", - headers: [ - { - key: "Cache-Control", - value: "public, max-age=120", - }, - ], - }, - { - source: "/c/[channelType]/[name]", - headers: [ - { - key: "Cache-Control", - value: "public, max-age=120", - }, - ], - }, - { - source: "/cart", - headers: [ - { - key: "Cache-Control", - value: "public, max-age=120", - }, - ], - }, - { - source: "/dashboard", - headers: [ - { - key: "Cache-Control", - value: "public, max-age=120", - }, - ], - }, - { - source: "/dashboard/[tab]", - headers: [ - { - key: "Cache-Control", - value: "public, max-age=120", - }, - ], - }, - { - source: "/dashboard/[tab]/[id]", - headers: [ - { - key: "Cache-Control", - value: "public, max-age=120", - }, - ], - }, - { - source: "/departments", - headers: [ - { - key: "Cache-Control", - value: "public, max-age=120", - }, - ], - }, - { - source: "/learningpaths", - headers: [ - { - key: "Cache-Control", - value: "public, max-age=120", - }, - ], - }, - { - source: "/learningpaths/[id]", - headers: [ - { - key: "Cache-Control", - value: "public, max-age=120", - }, - ], - }, - { - source: "/onboarding", - headers: [ - { - key: "Cache-Control", - value: "public, max-age=120", - }, - ], - }, - { - source: "/privacy", - headers: [ - { - key: "Cache-Control", - value: "public, max-age=120", - }, - ], - }, - { - source: "/program_letter", - headers: [ - { - key: "Cache-Control", - value: "public, max-age=120", - }, - ], - }, - { - source: "/program_letter/[id]", - headers: [ - { - key: "Cache-Control", - value: "public, max-age=120", - }, - ], - }, - { - source: "/program_letter/[id]/view", - headers: [ - { - key: "Cache-Control", - value: "public, max-age=120", - }, - ], - }, - { - source: "/search", - headers: [ - { - key: "Cache-Control", - value: "public, max-age=120", - }, - ], - }, - { - source: "/terms", - headers: [ - { - key: "Cache-Control", - value: "public, max-age=120", - }, - ], - }, - { - source: "/topics", - headers: [ - { - key: "Cache-Control", - value: "public, max-age=120", - }, - ], - }, + /* This is intended to target the base HTML responses. These are dynamically rendered, + * so Next.js instructs no-cache, however we are currently serving public content that + * is cacheable. Excludes everything with a file extension so we're matching only on routes. + */ { - source: "/unit", + // source: "/((?!_next/|.*\\.[a-zA-Z0-9]{2,4}$).*)", + source: "/((?!.*\\.[a-zA-Z0-9]{2,4}$).*)", headers: [ { key: "Cache-Control", From 8ebc4ea8a98c7d4cd9a9d32aeeb9494e21a2eb5d Mon Sep 17 00:00:00 2001 From: Jon Kafton <939376+jonkafton@users.noreply.github.com> Date: Wed, 16 Oct 2024 21:51:10 +0200 Subject: [PATCH 5/6] Remove middleware file --- frontends/main/next.config.js | 3 +- frontends/main/src/middleware.ts | 47 -------------------------------- 2 files changed, 1 insertion(+), 49 deletions(-) delete mode 100644 frontends/main/src/middleware.ts diff --git a/frontends/main/next.config.js b/frontends/main/next.config.js index c7943dda11..26e222626d 100644 --- a/frontends/main/next.config.js +++ b/frontends/main/next.config.js @@ -59,12 +59,11 @@ const nextConfig = { async headers() { return [ - /* This is intended to target the base HTML responses. These are dynamically rendered, + /* This is intended to target the base HTML responses. Some are dynamically rendered, * so Next.js instructs no-cache, however we are currently serving public content that * is cacheable. Excludes everything with a file extension so we're matching only on routes. */ { - // source: "/((?!_next/|.*\\.[a-zA-Z0-9]{2,4}$).*)", source: "/((?!.*\\.[a-zA-Z0-9]{2,4}$).*)", headers: [ { diff --git a/frontends/main/src/middleware.ts b/frontends/main/src/middleware.ts deleted file mode 100644 index b9238eb791..0000000000 --- a/frontends/main/src/middleware.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { NextResponse } from "next/server" -import type { NextRequest } from "next/server" - -export function middleware(_request: NextRequest) { - const response = NextResponse.next() - response.headers.set("Cache-Control", "public, max-age=120") - - return response -} - -export const config = { - /* The middleware matches on everything by default (all static files, js chunks, - * RSC payloads, etc.). It's safest to list out the paths here, although that does - * leave us with the maintenance overhead. - */ - matcher: [ - /* HTML responses. These are dynamically rendered, so Next.js instructs no-cache, - * however we are currently serving public content that is cacheable. */ - "/", - "/about", - "/c", - "/c/[channelType]", - "/c/[channelType]/[name]", - "/cart", - "/dashboard", - "/dashboard/[tab]", - "/dashboard/[tab]/[id]", - "/departments", - "/learningpaths", - "/learningpaths/[id]", - "/onboarding", - "/privacy", - "/program_letter", - "/program_letter/[id]", - "/program_letter/[id]/view", - "/search", - "/terms", - "/topics", - "/unit", - - /* Images rendered with the Next.js Image component have the cache header - * set on them, but CSS background images do not. - */ - "/images/(.*)", - "/favicon.ico", - ], -} From b23a32d9abfe124d8571860a10eef044eb6b9788 Mon Sep 17 00:00:00 2001 From: Jon Kafton <939376+jonkafton@users.noreply.github.com> Date: Thu, 17 Oct 2024 13:07:41 +0200 Subject: [PATCH 6/6] Instruct to only store in shared cache (not browsers) --- frontends/main/next.config.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontends/main/next.config.js b/frontends/main/next.config.js index 26e222626d..b068b3c220 100644 --- a/frontends/main/next.config.js +++ b/frontends/main/next.config.js @@ -68,7 +68,7 @@ const nextConfig = { headers: [ { key: "Cache-Control", - value: "public, max-age=120", + value: "s-maxage=120", }, ], }, @@ -81,7 +81,7 @@ const nextConfig = { headers: [ { key: "Cache-Control", - value: "public, max-age=600", + value: "s-maxage=600", }, ], }, @@ -90,7 +90,7 @@ const nextConfig = { headers: [ { key: "Cache-Control", - value: "public, max-age=31536000", + value: "s-maxage=31536000", }, ], },