From daed1fe2a0b3bed87f014bae169417a4a3fdb694 Mon Sep 17 00:00:00 2001 From: Aviv Keller Date: Sun, 21 Dec 2025 18:33:07 -0500 Subject: [PATCH 1/7] fix(static): fix static rendering --- .../app/[locale]/download/archive/[version]/page.tsx | 8 ++++---- apps/site/app/[locale]/not-found.tsx | 2 -- apps/site/components/EOL/EOLReleaseTable/index.tsx | 4 ++-- .../Releases/PreviousReleasesTable/index.tsx | 2 +- apps/site/components/withDownloadArchive.tsx | 4 ++-- apps/site/components/withDownloadSection.tsx | 4 ++-- apps/site/components/withNodeRelease.tsx | 11 ++++------- apps/site/components/withReleaseSelect.tsx | 6 ++---- apps/site/components/withSupporters.tsx | 6 ++---- apps/site/layouts/Download.tsx | 4 ++-- apps/site/next-data/providers/downloadSnippets.ts | 8 ++++---- apps/site/next-data/providers/releaseData.ts | 8 ++++++-- apps/site/next-data/providers/releaseVersions.ts | 8 ++++++-- apps/site/next-data/providers/supportersData.ts | 8 ++++++-- apps/site/next-data/providers/vulnerabilities.ts | 8 ++++++-- apps/site/next-env.d.ts | 2 +- apps/site/next.config.mjs | 1 - 17 files changed, 50 insertions(+), 44 deletions(-) diff --git a/apps/site/app/[locale]/download/archive/[version]/page.tsx b/apps/site/app/[locale]/download/archive/[version]/page.tsx index 5b6f358317cfd..5ef1baef58d42 100644 --- a/apps/site/app/[locale]/download/archive/[version]/page.tsx +++ b/apps/site/app/[locale]/download/archive/[version]/page.tsx @@ -24,13 +24,13 @@ export const generateMetadata = basePage.generateMetadata; // - If `ENABLE_STATIC_EXPORT_LOCALE` is true, generates paths for all available locales // - Otherwise, generates paths only for the default locale // @see https://nextjs.org/docs/app/api-reference/functions/generate-static-params -export const generateStaticParams = async () => { +export const generateStaticParams = () => { // Return an empty array if static export is disabled if (!ENABLE_STATIC_EXPORT) { return []; } - const versions = await provideReleaseVersions(); + const versions = provideReleaseVersions(); return versions.map(version => ({ locale: defaultLocale.code, @@ -49,14 +49,14 @@ const getPage: FC = async props => { const [locale, pathname] = basePage.getLocaleAndPath(version, routeLocale); if (version === 'current') { - const releaseData = await provideReleaseData(); + const releaseData = provideReleaseData(); const release = releaseData.find(release => release.status === 'Current'); redirect(`/${locale}/download/archive/${release?.versionWithPrefix}`); } - const versions = await provideReleaseVersions(); + const versions = provideReleaseVersions(); // Verifies if the current route is a dynamic route const isDynamicRoute = versions.some(r => r.includes(pathname)); diff --git a/apps/site/app/[locale]/not-found.tsx b/apps/site/app/[locale]/not-found.tsx index c6dc76a682af8..4dbfb3f5202df 100644 --- a/apps/site/app/[locale]/not-found.tsx +++ b/apps/site/app/[locale]/not-found.tsx @@ -1,5 +1,3 @@ -'use server'; - import { getTranslations } from 'next-intl/server'; import Button from '#site/components/Common/Button'; diff --git a/apps/site/components/EOL/EOLReleaseTable/index.tsx b/apps/site/components/EOL/EOLReleaseTable/index.tsx index 9116bdf8dd5f3..8dd358549cefb 100644 --- a/apps/site/components/EOL/EOLReleaseTable/index.tsx +++ b/apps/site/components/EOL/EOLReleaseTable/index.tsx @@ -12,8 +12,8 @@ import EOLReleaseTableBody from './TableBody'; import styles from './index.module.css'; const EOLReleaseTable: FC = async () => { - const releaseData = await provideReleaseData(); - const vulnerabilities = await provideVulnerabilities(); + const releaseData = provideReleaseData(); + const vulnerabilities = provideVulnerabilities(); const eolReleases = releaseData.filter( release => release.status === EOL_VERSION_IDENTIFIER diff --git a/apps/site/components/Releases/PreviousReleasesTable/index.tsx b/apps/site/components/Releases/PreviousReleasesTable/index.tsx index a018f0114732f..4a79ba333aeeb 100644 --- a/apps/site/components/Releases/PreviousReleasesTable/index.tsx +++ b/apps/site/components/Releases/PreviousReleasesTable/index.tsx @@ -7,7 +7,7 @@ import type { FC } from 'react'; import PreviousReleasesTableBody from './TableBody'; const PreviousReleasesTable: FC = async () => { - const releaseData = await provideReleaseData(); + const releaseData = provideReleaseData(); const t = await getTranslations(); diff --git a/apps/site/components/withDownloadArchive.tsx b/apps/site/components/withDownloadArchive.tsx index ec9f47b37fa95..da3d39e17c23d 100644 --- a/apps/site/components/withDownloadArchive.tsx +++ b/apps/site/components/withDownloadArchive.tsx @@ -19,7 +19,7 @@ type WithDownloadArchiveProps = { * Higher-order component that extracts version from pathname, * fetches release data, and provides download artifacts to child component */ -const WithDownloadArchive: FC = async ({ +const WithDownloadArchive: FC = ({ children: Component, }) => { const { pathname } = getClientContext(); @@ -28,7 +28,7 @@ const WithDownloadArchive: FC = async ({ const version = extractVersionFromPath(pathname); // Find the release data for the given version - const releaseData = await provideReleaseData(); + const releaseData = provideReleaseData(); const release = releaseData.find(release => // Match major version only (e.g., v22.x.x for release.major v22) version.startsWith(`v${release.major}`) diff --git a/apps/site/components/withDownloadSection.tsx b/apps/site/components/withDownloadSection.tsx index 3dcb3a1f5cc19..34a139a6a7138 100644 --- a/apps/site/components/withDownloadSection.tsx +++ b/apps/site/components/withDownloadSection.tsx @@ -22,11 +22,11 @@ const WithDownloadSection: FC = async ({ }) => { const locale = await getLocale(); - const snippets = await provideDownloadSnippets(locale); + const snippets = provideDownloadSnippets(locale); // By default the translated languages do not contain all the download snippets // Hence we always merge any translated snippet with the fallbacks for missing snippets - const fallbackSnippets = await provideDownloadSnippets(defaultLocale.code); + const fallbackSnippets = provideDownloadSnippets(defaultLocale.code); const { pathname } = getClientContext(); diff --git a/apps/site/components/withNodeRelease.tsx b/apps/site/components/withNodeRelease.tsx index f161c8939caf0..ae99fb103be6b 100644 --- a/apps/site/components/withNodeRelease.tsx +++ b/apps/site/components/withNodeRelease.tsx @@ -1,5 +1,3 @@ -'use server'; - import provideReleaseData from '#site/next-data/providers/releaseData'; import type { NodeRelease, NodeReleaseStatus } from '#site/types'; @@ -10,14 +8,13 @@ type WithNodeReleaseProps = { children: FC<{ release: NodeRelease }>; }; -// This is a React Async Server Component -// Note that Hooks cannot be used in a RSC async component -// Async Components do not get re-rendered at all. -const WithNodeRelease: FC = async ({ +// This is a React Server Component +// Note that Hooks cannot be used in a React Server Component +const WithNodeRelease: FC = ({ status: statuses, children: Component, }) => { - const releases = await provideReleaseData(); + const releases = provideReleaseData(); const matchingRelease = [statuses] .flat() diff --git a/apps/site/components/withReleaseSelect.tsx b/apps/site/components/withReleaseSelect.tsx index 64df156d05d88..dc7bfc85fdc56 100644 --- a/apps/site/components/withReleaseSelect.tsx +++ b/apps/site/components/withReleaseSelect.tsx @@ -1,5 +1,3 @@ -'use server'; - import StatelessSelect from '@node-core/ui-components/Common/Select/StatelessSelect'; import Link from '#site/components/Link'; @@ -43,8 +41,8 @@ type WithReleaseSelectProps = Omit< 'values' | 'as' >; -const WithReleaseSelect: FC = async ({ ...props }) => { - const releaseData = await provideReleaseData(); +const WithReleaseSelect: FC = ({ ...props }) => { + const releaseData = provideReleaseData(); const navigation = groupReleasesByStatus(releaseData); return ( diff --git a/apps/site/components/withSupporters.tsx b/apps/site/components/withSupporters.tsx index a75cac8f713fb..438808eae412b 100644 --- a/apps/site/components/withSupporters.tsx +++ b/apps/site/components/withSupporters.tsx @@ -1,13 +1,11 @@ -'use server'; - import provideSupporters from '#site/next-data/providers/supportersData'; import type { FC, PropsWithChildren } from 'react'; import SupportersList from './Common/Supporters'; -const WithSupporters: FC = async () => { - const supporters = await provideSupporters(); +const WithSupporters: FC = () => { + const supporters = provideSupporters(); return (
diff --git a/apps/site/layouts/Download.tsx b/apps/site/layouts/Download.tsx index cfd6501b10678..6c74c4056c472 100644 --- a/apps/site/layouts/Download.tsx +++ b/apps/site/layouts/Download.tsx @@ -8,10 +8,10 @@ import type { FC, PropsWithChildren } from 'react'; import styles from './layouts.module.css'; -const DownloadLayout: FC = async ({ children }) => { +const DownloadLayout: FC = ({ children }) => { const { frontmatter } = getClientContext(); - const releases = await provideReleaseData(); + const releases = provideReleaseData(); return ( <> diff --git a/apps/site/next-data/providers/downloadSnippets.ts b/apps/site/next-data/providers/downloadSnippets.ts index 2c1674ad0f9c8..3467d02838275 100644 --- a/apps/site/next-data/providers/downloadSnippets.ts +++ b/apps/site/next-data/providers/downloadSnippets.ts @@ -1,15 +1,15 @@ -'use cache'; +import { cache } from 'react'; import generateDownloadSnippets from '#site/next-data/generators/downloadSnippets.mjs'; -const provideDownloadSnippets = async (language: string) => { - const downloadSnippets = await generateDownloadSnippets(); +const downloadSnippets = await generateDownloadSnippets(); +const provideDownloadSnippets = cache((language: string) => { if (downloadSnippets.has(language)) { return downloadSnippets.get(language)!; } return []; -}; +}); export default provideDownloadSnippets; diff --git a/apps/site/next-data/providers/releaseData.ts b/apps/site/next-data/providers/releaseData.ts index c063dd8fd5ea5..04f37ac05eeda 100644 --- a/apps/site/next-data/providers/releaseData.ts +++ b/apps/site/next-data/providers/releaseData.ts @@ -1,5 +1,9 @@ -'use cache'; +import { cache } from 'react'; -import provideReleaseData from '#site/next-data/generators/releaseData.mjs'; +import generateReleaseData from '#site/next-data/generators/releaseData.mjs'; + +const releaseData = await generateReleaseData(); + +const provideReleaseData = cache(() => releaseData); export default provideReleaseData; diff --git a/apps/site/next-data/providers/releaseVersions.ts b/apps/site/next-data/providers/releaseVersions.ts index d9aa33346dc41..580054daf0005 100644 --- a/apps/site/next-data/providers/releaseVersions.ts +++ b/apps/site/next-data/providers/releaseVersions.ts @@ -1,5 +1,9 @@ -'use cache'; +import { cache } from 'react'; -import provideReleaseVersions from '#site/next-data/generators/releaseVersions.mjs'; +import generateReleaseVersions from '#site/next-data/generators/releaseVersions.mjs'; + +const releaseVersions = await generateReleaseVersions(); + +const provideReleaseVersions = cache(() => releaseVersions); export default provideReleaseVersions; diff --git a/apps/site/next-data/providers/supportersData.ts b/apps/site/next-data/providers/supportersData.ts index e6e34a6877590..c3cbdb126aea4 100644 --- a/apps/site/next-data/providers/supportersData.ts +++ b/apps/site/next-data/providers/supportersData.ts @@ -1,5 +1,9 @@ -'use cache'; +import { cache } from 'react'; -import provideSupporters from '#site/next-data/generators/supportersData.mjs'; +import generateSupporters from '#site/next-data/generators/supportersData.mjs'; + +const supportersData = await generateSupporters(); + +const provideSupporters = cache(() => supportersData); export default provideSupporters; diff --git a/apps/site/next-data/providers/vulnerabilities.ts b/apps/site/next-data/providers/vulnerabilities.ts index e360781eebd10..cfc3cce008ba0 100644 --- a/apps/site/next-data/providers/vulnerabilities.ts +++ b/apps/site/next-data/providers/vulnerabilities.ts @@ -1,5 +1,9 @@ -'use cache'; +import { cache } from 'react'; -import provideVulnerabilities from '#site/next-data/generators/vulnerabilities.mjs'; +import generateVulnerabilities from '#site/next-data/generators/vulnerabilities.mjs'; + +const vulnerabilities = await generateVulnerabilities(); + +const provideVulnerabilities = cache(() => vulnerabilities); export default provideVulnerabilities; diff --git a/apps/site/next-env.d.ts b/apps/site/next-env.d.ts index 2d5420ebae639..cdb6b7b848c32 100644 --- a/apps/site/next-env.d.ts +++ b/apps/site/next-env.d.ts @@ -1,7 +1,7 @@ /// /// /// -import "./.next/types/routes.d.ts"; +import './.next/dev/types/routes.d.ts'; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/apps/site/next.config.mjs b/apps/site/next.config.mjs index c8f6bc2c4d290..fa4f0256b90c2 100644 --- a/apps/site/next.config.mjs +++ b/apps/site/next.config.mjs @@ -55,7 +55,6 @@ const nextConfig = { typedRoutes: true, // Experimental Flags experimental: { - useCache: true, // Ensure that server-side code is also minified serverMinification: true, // Use Workers and Threads for webpack compilation From 1fedc01337ac0edb2c69d0cc6a219a2cb7844cb4 Mon Sep 17 00:00:00 2001 From: Aviv Keller Date: Sun, 21 Dec 2025 18:41:31 -0500 Subject: [PATCH 2/7] fixup! --- .github/workflows/build.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c0856da7579ba..057e16cf9dc44 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -67,8 +67,6 @@ jobs: # this should be a last resort in case by any chances the build memory gets too high # but in general this should never happen NODE_OPTIONS: '--max_old_space_size=4096' - # We want to ensure that static exports for all locales do not occur on `pull_request` events - NEXT_PUBLIC_STATIC_EXPORT_LOCALE: ${{ github.event_name == 'push' }} # See https://github.com/vercel/next.js/pull/81318 TURBOPACK_STATS: ${{ matrix.os == 'ubuntu-latest' }} @@ -77,3 +75,14 @@ jobs: with: name: webpack-stats path: apps/site/.next/server/webpack-stats.json + + - name: Build Next.js (Static Default Locale) + # We want to generate a static build, as it is a requirement of our website. + run: node_modules/.bin/turbo deploy ${{ env.TURBO_ARGS }} + env: + # We want to ensure we have enough RAM allocated to the Node.js process + # this should be a last resort in case by any chances the build memory gets too high + # but in general this should never happen + NODE_OPTIONS: '--max_old_space_size=4096' + # We want to ensure that static exports for all locales do not occur on `pull_request` events + NEXT_PUBLIC_STATIC_EXPORT_LOCALE: ${{ github.event_name == 'push' }} From 0986d380fc525e323ebc227de25625d9b0e7d744 Mon Sep 17 00:00:00 2001 From: Aviv Keller Date: Sun, 21 Dec 2025 18:43:04 -0500 Subject: [PATCH 3/7] fixup! use async anyway --- apps/site/app/[locale]/download/archive/[version]/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/site/app/[locale]/download/archive/[version]/page.tsx b/apps/site/app/[locale]/download/archive/[version]/page.tsx index 5ef1baef58d42..8a64f9f24bc62 100644 --- a/apps/site/app/[locale]/download/archive/[version]/page.tsx +++ b/apps/site/app/[locale]/download/archive/[version]/page.tsx @@ -24,7 +24,7 @@ export const generateMetadata = basePage.generateMetadata; // - If `ENABLE_STATIC_EXPORT_LOCALE` is true, generates paths for all available locales // - Otherwise, generates paths only for the default locale // @see https://nextjs.org/docs/app/api-reference/functions/generate-static-params -export const generateStaticParams = () => { +export const generateStaticParams = async () => { // Return an empty array if static export is disabled if (!ENABLE_STATIC_EXPORT) { return []; From 403707ee008c2babf45cfee06ce98b18a24ebc0a Mon Sep 17 00:00:00 2001 From: Aviv Keller Date: Sun, 21 Dec 2025 18:59:31 -0500 Subject: [PATCH 4/7] fixup! async caching --- .../app/[locale]/download/archive/[version]/page.tsx | 6 +++--- apps/site/components/EOL/EOLReleaseTable/index.tsx | 4 ++-- .../Releases/PreviousReleasesTable/index.tsx | 2 +- apps/site/components/withDownloadArchive.tsx | 4 ++-- apps/site/components/withDownloadSection.tsx | 10 ++++++---- apps/site/components/withNodeRelease.tsx | 4 ++-- apps/site/components/withReleaseSelect.tsx | 4 ++-- apps/site/components/withSupporters.tsx | 4 ++-- apps/site/layouts/Download.tsx | 4 ++-- apps/site/next-data/providers/downloadSnippets.ts | 12 +----------- apps/site/next-data/providers/releaseData.ts | 6 +----- apps/site/next-data/providers/releaseVersions.ts | 6 +----- apps/site/next-data/providers/supportersData.ts | 6 +----- apps/site/next-data/providers/vulnerabilities.ts | 6 +----- 14 files changed, 27 insertions(+), 51 deletions(-) diff --git a/apps/site/app/[locale]/download/archive/[version]/page.tsx b/apps/site/app/[locale]/download/archive/[version]/page.tsx index 8a64f9f24bc62..5b6f358317cfd 100644 --- a/apps/site/app/[locale]/download/archive/[version]/page.tsx +++ b/apps/site/app/[locale]/download/archive/[version]/page.tsx @@ -30,7 +30,7 @@ export const generateStaticParams = async () => { return []; } - const versions = provideReleaseVersions(); + const versions = await provideReleaseVersions(); return versions.map(version => ({ locale: defaultLocale.code, @@ -49,14 +49,14 @@ const getPage: FC = async props => { const [locale, pathname] = basePage.getLocaleAndPath(version, routeLocale); if (version === 'current') { - const releaseData = provideReleaseData(); + const releaseData = await provideReleaseData(); const release = releaseData.find(release => release.status === 'Current'); redirect(`/${locale}/download/archive/${release?.versionWithPrefix}`); } - const versions = provideReleaseVersions(); + const versions = await provideReleaseVersions(); // Verifies if the current route is a dynamic route const isDynamicRoute = versions.some(r => r.includes(pathname)); diff --git a/apps/site/components/EOL/EOLReleaseTable/index.tsx b/apps/site/components/EOL/EOLReleaseTable/index.tsx index 8dd358549cefb..9116bdf8dd5f3 100644 --- a/apps/site/components/EOL/EOLReleaseTable/index.tsx +++ b/apps/site/components/EOL/EOLReleaseTable/index.tsx @@ -12,8 +12,8 @@ import EOLReleaseTableBody from './TableBody'; import styles from './index.module.css'; const EOLReleaseTable: FC = async () => { - const releaseData = provideReleaseData(); - const vulnerabilities = provideVulnerabilities(); + const releaseData = await provideReleaseData(); + const vulnerabilities = await provideVulnerabilities(); const eolReleases = releaseData.filter( release => release.status === EOL_VERSION_IDENTIFIER diff --git a/apps/site/components/Releases/PreviousReleasesTable/index.tsx b/apps/site/components/Releases/PreviousReleasesTable/index.tsx index 4a79ba333aeeb..a018f0114732f 100644 --- a/apps/site/components/Releases/PreviousReleasesTable/index.tsx +++ b/apps/site/components/Releases/PreviousReleasesTable/index.tsx @@ -7,7 +7,7 @@ import type { FC } from 'react'; import PreviousReleasesTableBody from './TableBody'; const PreviousReleasesTable: FC = async () => { - const releaseData = provideReleaseData(); + const releaseData = await provideReleaseData(); const t = await getTranslations(); diff --git a/apps/site/components/withDownloadArchive.tsx b/apps/site/components/withDownloadArchive.tsx index da3d39e17c23d..ec9f47b37fa95 100644 --- a/apps/site/components/withDownloadArchive.tsx +++ b/apps/site/components/withDownloadArchive.tsx @@ -19,7 +19,7 @@ type WithDownloadArchiveProps = { * Higher-order component that extracts version from pathname, * fetches release data, and provides download artifacts to child component */ -const WithDownloadArchive: FC = ({ +const WithDownloadArchive: FC = async ({ children: Component, }) => { const { pathname } = getClientContext(); @@ -28,7 +28,7 @@ const WithDownloadArchive: FC = ({ const version = extractVersionFromPath(pathname); // Find the release data for the given version - const releaseData = provideReleaseData(); + const releaseData = await provideReleaseData(); const release = releaseData.find(release => // Match major version only (e.g., v22.x.x for release.major v22) version.startsWith(`v${release.major}`) diff --git a/apps/site/components/withDownloadSection.tsx b/apps/site/components/withDownloadSection.tsx index 34a139a6a7138..61895f345f6bf 100644 --- a/apps/site/components/withDownloadSection.tsx +++ b/apps/site/components/withDownloadSection.tsx @@ -22,19 +22,21 @@ const WithDownloadSection: FC = async ({ }) => { const locale = await getLocale(); - const snippets = provideDownloadSnippets(locale); + const snippets = await provideDownloadSnippets(); + + const localeSnippets = snippets.get(locale) ?? []; // By default the translated languages do not contain all the download snippets // Hence we always merge any translated snippet with the fallbacks for missing snippets - const fallbackSnippets = provideDownloadSnippets(defaultLocale.code); + const fallbackSnippets = snippets.get(defaultLocale.code) ?? []; const { pathname } = getClientContext(); // Some available translations do not have download snippets translated or have them partially translated // This aims to merge the available translated snippets with the fallback snippets const memoizedSnippets = fallbackSnippets - .filter(snippet => !snippets.some(s => s.name === snippet.name)) - .concat(snippets); + .filter(snippet => !localeSnippets.some(s => s.name === snippet.name)) + .concat(localeSnippets); // Decides which initial release to use based on the current pathname const initialRelease = pathname.endsWith('/current') diff --git a/apps/site/components/withNodeRelease.tsx b/apps/site/components/withNodeRelease.tsx index ae99fb103be6b..2d658b64b08a1 100644 --- a/apps/site/components/withNodeRelease.tsx +++ b/apps/site/components/withNodeRelease.tsx @@ -10,11 +10,11 @@ type WithNodeReleaseProps = { // This is a React Server Component // Note that Hooks cannot be used in a React Server Component -const WithNodeRelease: FC = ({ +const WithNodeRelease: FC = async ({ status: statuses, children: Component, }) => { - const releases = provideReleaseData(); + const releases = await provideReleaseData(); const matchingRelease = [statuses] .flat() diff --git a/apps/site/components/withReleaseSelect.tsx b/apps/site/components/withReleaseSelect.tsx index dc7bfc85fdc56..53a7469212988 100644 --- a/apps/site/components/withReleaseSelect.tsx +++ b/apps/site/components/withReleaseSelect.tsx @@ -41,8 +41,8 @@ type WithReleaseSelectProps = Omit< 'values' | 'as' >; -const WithReleaseSelect: FC = ({ ...props }) => { - const releaseData = provideReleaseData(); +const WithReleaseSelect: FC = async ({ ...props }) => { + const releaseData = await provideReleaseData(); const navigation = groupReleasesByStatus(releaseData); return ( diff --git a/apps/site/components/withSupporters.tsx b/apps/site/components/withSupporters.tsx index 438808eae412b..876035b78458d 100644 --- a/apps/site/components/withSupporters.tsx +++ b/apps/site/components/withSupporters.tsx @@ -4,8 +4,8 @@ import type { FC, PropsWithChildren } from 'react'; import SupportersList from './Common/Supporters'; -const WithSupporters: FC = () => { - const supporters = provideSupporters(); +const WithSupporters: FC = async () => { + const supporters = await provideSupporters(); return (
diff --git a/apps/site/layouts/Download.tsx b/apps/site/layouts/Download.tsx index 6c74c4056c472..cfd6501b10678 100644 --- a/apps/site/layouts/Download.tsx +++ b/apps/site/layouts/Download.tsx @@ -8,10 +8,10 @@ import type { FC, PropsWithChildren } from 'react'; import styles from './layouts.module.css'; -const DownloadLayout: FC = ({ children }) => { +const DownloadLayout: FC = async ({ children }) => { const { frontmatter } = getClientContext(); - const releases = provideReleaseData(); + const releases = await provideReleaseData(); return ( <> diff --git a/apps/site/next-data/providers/downloadSnippets.ts b/apps/site/next-data/providers/downloadSnippets.ts index 3467d02838275..5aa909bda3915 100644 --- a/apps/site/next-data/providers/downloadSnippets.ts +++ b/apps/site/next-data/providers/downloadSnippets.ts @@ -2,14 +2,4 @@ import { cache } from 'react'; import generateDownloadSnippets from '#site/next-data/generators/downloadSnippets.mjs'; -const downloadSnippets = await generateDownloadSnippets(); - -const provideDownloadSnippets = cache((language: string) => { - if (downloadSnippets.has(language)) { - return downloadSnippets.get(language)!; - } - - return []; -}); - -export default provideDownloadSnippets; +export default cache(generateDownloadSnippets); diff --git a/apps/site/next-data/providers/releaseData.ts b/apps/site/next-data/providers/releaseData.ts index 04f37ac05eeda..853cffd03d09d 100644 --- a/apps/site/next-data/providers/releaseData.ts +++ b/apps/site/next-data/providers/releaseData.ts @@ -2,8 +2,4 @@ import { cache } from 'react'; import generateReleaseData from '#site/next-data/generators/releaseData.mjs'; -const releaseData = await generateReleaseData(); - -const provideReleaseData = cache(() => releaseData); - -export default provideReleaseData; +export default cache(generateReleaseData); diff --git a/apps/site/next-data/providers/releaseVersions.ts b/apps/site/next-data/providers/releaseVersions.ts index 580054daf0005..a057e76f7264c 100644 --- a/apps/site/next-data/providers/releaseVersions.ts +++ b/apps/site/next-data/providers/releaseVersions.ts @@ -2,8 +2,4 @@ import { cache } from 'react'; import generateReleaseVersions from '#site/next-data/generators/releaseVersions.mjs'; -const releaseVersions = await generateReleaseVersions(); - -const provideReleaseVersions = cache(() => releaseVersions); - -export default provideReleaseVersions; +export default cache(generateReleaseVersions); diff --git a/apps/site/next-data/providers/supportersData.ts b/apps/site/next-data/providers/supportersData.ts index c3cbdb126aea4..cb5c161ba09bf 100644 --- a/apps/site/next-data/providers/supportersData.ts +++ b/apps/site/next-data/providers/supportersData.ts @@ -2,8 +2,4 @@ import { cache } from 'react'; import generateSupporters from '#site/next-data/generators/supportersData.mjs'; -const supportersData = await generateSupporters(); - -const provideSupporters = cache(() => supportersData); - -export default provideSupporters; +export default cache(generateSupporters); diff --git a/apps/site/next-data/providers/vulnerabilities.ts b/apps/site/next-data/providers/vulnerabilities.ts index cfc3cce008ba0..508a1cc95efef 100644 --- a/apps/site/next-data/providers/vulnerabilities.ts +++ b/apps/site/next-data/providers/vulnerabilities.ts @@ -2,8 +2,4 @@ import { cache } from 'react'; import generateVulnerabilities from '#site/next-data/generators/vulnerabilities.mjs'; -const vulnerabilities = await generateVulnerabilities(); - -const provideVulnerabilities = cache(() => vulnerabilities); - -export default provideVulnerabilities; +export default cache(generateVulnerabilities); From 93f3ea10b4208532bc2cb3329d182886b24b8998 Mon Sep 17 00:00:00 2001 From: Aviv Keller Date: Sun, 21 Dec 2025 19:01:40 -0500 Subject: [PATCH 5/7] fixup! --- apps/site/components/withNodeRelease.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/site/components/withNodeRelease.tsx b/apps/site/components/withNodeRelease.tsx index 2d658b64b08a1..bdacc99f8e121 100644 --- a/apps/site/components/withNodeRelease.tsx +++ b/apps/site/components/withNodeRelease.tsx @@ -8,8 +8,9 @@ type WithNodeReleaseProps = { children: FC<{ release: NodeRelease }>; }; -// This is a React Server Component -// Note that Hooks cannot be used in a React Server Component +// This is a React Async Server Component +// Note that Hooks cannot be used in a RSC async component +// Async Components do not get re-rendered at all. const WithNodeRelease: FC = async ({ status: statuses, children: Component, From 8fb35c8ca5cc5ab54481062d6901bc852bad679d Mon Sep 17 00:00:00 2001 From: Aviv Keller Date: Sun, 21 Dec 2025 19:11:19 -0500 Subject: [PATCH 6/7] Update .github/workflows/build.yml Co-authored-by: Claudio Wunder Signed-off-by: Aviv Keller --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 057e16cf9dc44..af838056c57e3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -76,7 +76,7 @@ jobs: name: webpack-stats path: apps/site/.next/server/webpack-stats.json - - name: Build Next.js (Static Default Locale) + - name: Build Next.js (Static Export) # We want to generate a static build, as it is a requirement of our website. run: node_modules/.bin/turbo deploy ${{ env.TURBO_ARGS }} env: From 351ca03047c60c04f9e720222de6700bdec9eb4d Mon Sep 17 00:00:00 2001 From: Aviv Keller Date: Mon, 22 Dec 2025 14:51:42 -0500 Subject: [PATCH 7/7] fixup! --- apps/site/next-data/generators/majorNodeReleases.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/site/next-data/generators/majorNodeReleases.mjs b/apps/site/next-data/generators/majorNodeReleases.mjs index 7988067b63040..0a9a06e8cd5e4 100644 --- a/apps/site/next-data/generators/majorNodeReleases.mjs +++ b/apps/site/next-data/generators/majorNodeReleases.mjs @@ -2,12 +2,12 @@ import nodevu from '@nodevu/core'; -const nodevuData = await nodevu({ fetch }); - /** * Filters Node.js release data to return only major releases with documented support. */ export default async function getMajorNodeReleases() { + const nodevuData = await nodevu({ fetch }); + return Object.entries(nodevuData).filter(([version, { support }]) => { // Filter out those without documented support // Basically those not in schedule.json