Skip to content

Commit

Permalink
fix: we should invalidate data over time (nodejs#6153)
Browse files Browse the repository at this point in the history
  • Loading branch information
ovflowd authored Nov 30, 2023
1 parent f292c26 commit 80af3e1
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 18 deletions.
1 change: 1 addition & 0 deletions app/[locale]/[[...path]]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ const getPage: FC<DynamicParams> = async ({ params }) => {
export const dynamicParams = true;

// Enforces that this route is used as static rendering
// Except whenever on the Development mode as we want instant-refresh when making changes
// @see https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#dynamic
export const dynamic = 'error';

Expand Down
6 changes: 6 additions & 0 deletions app/[locale]/next-data/blog-data/[category]/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import provideBlogData from '@/next-data/providers/blogData';
import { VERCEL_EVALIDATE_TIME } from '@/next.constants.mjs';
import { defaultLocale } from '@/next.locales.mjs';

// We only support fetching these pages from the /en/ locale code
Expand Down Expand Up @@ -40,3 +41,8 @@ export const dynamicParams = false;
// Enforces that this route is cached and static as much as possible
// @see https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#dynamic
export const dynamic = 'error';

// Ensures that this endpoint is invalidated and re-executed every X minutes
// so that when new deployments happen, the data is refreshed
// @see https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#revalidate
export const revalidate = VERCEL_EVALIDATE_TIME;
8 changes: 7 additions & 1 deletion app/[locale]/next-data/release-data/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import provideReleaseData from '@/next-data/providers/releaseData';
import { VERCEL_EVALIDATE_TIME } from '@/next.constants.mjs';
import { defaultLocale } from '@/next.locales.mjs';

// We only support fetching these pages from the /en/ locale code
Expand All @@ -18,10 +19,15 @@ export const GET = async () => {
// This is used for ISR static validation and generation
export const generateStaticParams = async () => [{ locale }];

// Forces that only the paths from `generateStaticParams` are allowed, giving 404 on the contrary
// Enforces that only the paths from `generateStaticParams` are allowed, giving 404 on the contrary
// @see https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#dynamicparams
export const dynamicParams = false;

// Enforces that this route is used as static rendering
// @see https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#dynamic
export const dynamic = 'error';

// Ensures that this endpoint is invalidated and re-executed every X minutes
// so that when new deployments happen, the data is refreshed
// @see https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#revalidate
export const revalidate = VERCEL_EVALIDATE_TIME;
9 changes: 7 additions & 2 deletions next-data/blogData.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { ENABLE_STATIC_EXPORT, NEXT_DATA_URL } from '@/next.constants.mjs';
import {
ENABLE_STATIC_EXPORT,
IS_DEVELOPMENT,
NEXT_DATA_URL,
VERCEL_ENV,
} from '@/next.constants.mjs';
import type { BlogDataRSC } from '@/types';

const getBlogData = (category: string): Promise<BlogDataRSC> => {
// When we're using Static Exports the Next.js Server is not running (during build-time)
// hence the self-ingestion APIs will not be available. In this case we want to load
// the data directly within the current thread, which will anyways be loaded only once
// We use lazy-imports to prevent `provideBlogData` from executing on import
if (ENABLE_STATIC_EXPORT) {
if (ENABLE_STATIC_EXPORT || (!IS_DEVELOPMENT && !VERCEL_ENV)) {
return import('@/next-data/providers/blogData').then(
({ default: provideBlogData }) => provideBlogData(category)
);
Expand Down
9 changes: 7 additions & 2 deletions next-data/releaseData.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { ENABLE_STATIC_EXPORT, NEXT_DATA_URL } from '@/next.constants.mjs';
import {
ENABLE_STATIC_EXPORT,
IS_DEVELOPMENT,
NEXT_DATA_URL,
VERCEL_ENV,
} from '@/next.constants.mjs';
import type { NodeRelease } from '@/types';

const getReleaseData = (): Promise<NodeRelease[]> => {
// When we're using Static Exports the Next.js Server is not running (during build-time)
// hence the self-ingestion APIs will not be available. In this case we want to load
// the data directly within the current thread, which will anyways be loaded only once
// We use lazy-imports to prevent `provideBlogData` from executing on import
if (ENABLE_STATIC_EXPORT) {
if (ENABLE_STATIC_EXPORT || (!IS_DEVELOPMENT && !VERCEL_ENV)) {
return import('@/next-data/providers/releaseData').then(
({ default: provideReleaseData }) => provideReleaseData()
);
Expand Down
28 changes: 23 additions & 5 deletions next.constants.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@ export const IS_DEVELOPMENT = process.env.NODE_ENV === 'development';
*/
export const VERCEL_ENV = process.env.NEXT_PUBLIC_VERCEL_ENV || undefined;

/**
* This is used for defining a default time of when `next-data` and other dynamically generated
* but static-enabled pages should be regenerated.
*
* Note that this is a custom Environment Variable that can be defined by us when necessary
*/
export const VERCEL_EVALIDATE_TIME = Number(
process.env.NEXT_PUBLIC_VERCEL_REVALIDATE_TIME || 300
);

/**
* This is used for telling Next.js to to a Static Export Build of the Website
*
Expand Down Expand Up @@ -50,15 +60,15 @@ export const BASE_URL = process.env.NEXT_PUBLIC_BASE_URL
/**
* This is used for any place that requires the Node.js distribution URL (which by default is nodejs.org/dist)
*
* Note that this is a manual Environment Variable defined by us if necessary.
* Note that this is a custom Environment Variable that can be defined by us when necessary
*/
export const DIST_URL =
process.env.NEXT_PUBLIC_DIST_URL || 'https://nodejs.org/dist/';

/**
* This is used for any place that requires the Node.js API Docs URL (which by default is nodejs.org/docs)
*
* Note that this is a manual Environment Variable defined by us if necessary.
* Note that this is a custom Environment Variable that can be defined by us when necessary
*/
export const DOCS_URL =
process.env.NEXT_PUBLIC_DOCS_URL || 'https://nodejs.org/docs/';
Expand All @@ -69,7 +79,7 @@ export const DOCS_URL =
* This is useful when running the deployment on a subdirectory
* of a domain, such as when hosted on GitHub Pages.
*
* Note that this is a manual Environment Variable defined by us if necessary.
* Note that this is a custom Environment Variable that can be defined by us when necessary
*/
export const BASE_PATH = process.env.NEXT_PUBLIC_BASE_PATH || '';

Expand Down Expand Up @@ -112,6 +122,8 @@ export const EXTERNAL_LINKS_SITEMAP = [

/**
* The `localStorage` key to store the theme choice of `next-themes`
*
* This is what allows us to store user preference for theming
*/
export const THEME_STORAGE_KEY = 'theme';

Expand All @@ -123,19 +135,25 @@ export const SENTRY_DSN =

/**
* This states if Sentry should be enabled and bundled within our App
*
* We enable sentry by default if we're om development mode or deployed
* on Vercel (either production or preview branches)
*/
export const SENTRY_ENABLE = IS_DEVELOPMENT || !!VERCEL_ENV;

/**
* This configures the sampling rate for Sentry
*
* @note we always want to capture 100% on preview branches and development mode
* We always want to capture 100% on Vercel Preview Branches
* and not when it's on Production Mode (nodejs.org)
*/
export const SENTRY_CAPTURE_RATE =
SENTRY_ENABLE && BASE_URL !== 'https://nodejs.org' ? 1.0 : 0.01;
SENTRY_ENABLE && VERCEL_ENV && BASE_URL !== 'https://nodejs.org' ? 1.0 : 0.01;

/**
* Provides the Route for Sentry's Server-Side Tunnel
*
* This is a `@sentry/nextjs` specific feature
*/
export const SENTRY_TUNNEL = (components = '') =>
SENTRY_ENABLE ? `/monitoring${components}` : undefined;
Expand Down
38 changes: 30 additions & 8 deletions next.dynamic.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ import matter from 'gray-matter';
import { cache } from 'react';
import { VFile } from 'vfile';

import { MD_EXTENSION_REGEX, BASE_URL, BASE_PATH } from './next.constants.mjs';
import {
MD_EXTENSION_REGEX,
BASE_URL,
BASE_PATH,
IS_DEVELOPMENT,
} from './next.constants.mjs';
import {
DYNAMIC_ROUTES_IGNORES,
DYNAMIC_ROUTES_REWRITES,
Expand Down Expand Up @@ -47,8 +52,25 @@ const mapPathToRoute = (locale = defaultLocale.code, path = '') => ({
path: path.split(sep),
});

// Provides an in-memory Map that lasts the whole build process
// and disabled when on development mode (stubbed)
const createCachedMarkdownCache = () => {
if (IS_DEVELOPMENT) {
return {
has: () => false,
set: () => {},
get: () => null,
};
}

return new Map();
};

const getDynamicRouter = async () => {
const cachedMarkdownFiles = new Map();
// Creates a Cache System that is disabled during development mode
const cachedMarkdownFiles = createCachedMarkdownCache();

// Keeps the map of pathnames to filenames
const pathnameToFilename = new Map();

const websitePages = await getMarkdownFiles(
Expand Down Expand Up @@ -131,7 +153,7 @@ const getDynamicRouter = async () => {

// We then attempt to retrieve the source version of the file as there is no localised version
// of the file and we set it on the cache to prevent future checks of the same locale for this file
const { source: fileContent } = getMarkdownFile(
const { source: fileContent } = _getMarkdownFile(
defaultLocale.code,
pathname
);
Expand Down Expand Up @@ -217,13 +239,13 @@ const getDynamicRouter = async () => {
});

return {
getRoutesByLanguage,
getMarkdownFile,
getMDXContent,
getPathname,
mapPathToRoute,
shouldIgnoreRoute,
getPathname,
getRouteRewrite,
mapPathToRoute,
getRoutesByLanguage,
getMDXContent,
getMarkdownFile,
getPageMetadata,
};
};
Expand Down

0 comments on commit 80af3e1

Please sign in to comment.