Skip to content

Commit

Permalink
feat: introducing cache controls
Browse files Browse the repository at this point in the history
  • Loading branch information
nicholasio committed Apr 1, 2024
1 parent 07f648a commit ac0bcc0
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 22 deletions.
31 changes: 20 additions & 11 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion packages/next/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@
"deepmerge": "^4.3.1",
"@headstartwp/core": "^1.3.4",
"loader-utils": "^3.2.0",
"schema-utils": "^4.0.0"
"schema-utils": "^4.0.0",
"@isaacs/ttlcache": "^1.4.1"
},
"devDependencies": {
"@testing-library/dom": "^8.19.0",
Expand Down
6 changes: 6 additions & 0 deletions packages/next/src/data/server/cache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import TTLCache from '@isaacs/ttlcache';

const kTTLCache = Symbol.for('ttlcache');
const g = globalThis as typeof globalThis & { [kTTLCache]?: TTLCache<string, any> };
g[kTTLCache] ??= new TTLCache({ max: 10000 });
export const cache = g[kTTLCache];
69 changes: 61 additions & 8 deletions packages/next/src/data/server/fetchHookData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import deepmerge from 'deepmerge';
import { PreviewData } from '../../handlers/types';
import { convertToPath } from '../convertToPath';
import { getSiteFromContext } from './getSiteFromContext';
import { cache } from './cache';

/**
* The supported options for {@link fetchHookData}
Expand All @@ -32,6 +33,26 @@ export interface FetchHookDataOptions<P = unknown, T = unknown> {
* Optional. If set, will forward fetch options to the fetch strategy
*/
fetchStrategyOptions?: Partial<FetchOptions>;

/**
* Controls server-side caching
*/
cache?: {
/**
* TTL in milliseconds
*/
ttl?: number;

/**
* Whether it should cache this request
*/
enabled: boolean;

/**
* The cache strategy
*/
strategy?: 'lru';
};
}

function isPreviewRequest<P>(params: P, urlParams: P): params is P & PostParams {
Expand Down Expand Up @@ -63,6 +84,9 @@ export function prepareFetchHookData<T = unknown, P extends EndpointParams = End
ctx: GetServerSidePropsContext<any, PreviewData> | GetStaticPropsContext<any, PreviewData>,
options: FetchHookDataOptions<P, T> = {},
) {
// should never cache when cache is not enabled, or when is previewing or when burstCache is set to true
const shouldCache = (options?.cache?.enabled ?? false) && !ctx.preview;

const { sourceUrl, integrations } = getSiteFromContext(ctx);
const params: Partial<P> = options?.params || {};

Expand All @@ -89,6 +113,7 @@ export function prepareFetchHookData<T = unknown, P extends EndpointParams = End
params: finalParams,
urlParams,
path: stringPath,
shouldCache,
};
}

Expand Down Expand Up @@ -116,7 +141,7 @@ export function prepareFetchHookData<T = unknown, P extends EndpointParams = End
* @param fetchStrategy The fetch strategy to use. Typically this is exposed by the hook e.g: `usePosts.fetcher()`
* @param ctx The Next.js context, either the one from `getServerSideProps` or `getStaticProps`
* @param options See {@link FetchHookDataOptions}
*
* @returns An object with a key of `data` and a value of the fetched data.
*
* @category Next.js Data Fetching Utilities
Expand All @@ -131,6 +156,7 @@ export async function fetchHookData<T = unknown, P extends EndpointParams = Endp
params,
urlParams,
path,
shouldCache,
} = prepareFetchHookData(fetchStrategy, ctx, options);

const { debug, preview } = getSiteFromContext(ctx);
Expand Down Expand Up @@ -166,12 +192,39 @@ export async function fetchHookData<T = unknown, P extends EndpointParams = Endp
}
}

const data = await fetchStrategy.fetcher(fetchStrategy.buildEndpointURL(params), params, {
// burst cache to skip REST API cache when the request is being made under getStaticProps
// if .req is not available then this is a GetStaticPropsContext
burstCache: typeof (ctx as GetServerSidePropsContext).req === 'undefined',
...options.fetchStrategyOptions,
});
let data;
const cacheKey = serializeKey(key);

if (shouldCache) {
data = await cache.get(cacheKey);

if (debug?.devMode) {
if (data) {
log(LOGTYPE.INFO, `[fetchHookData] cache hit for ${cacheKey}`);
} else {
log(LOGTYPE.INFO, `[fetchHookData] cache miss for ${cacheKey}`, ctx);
}
}
}

if (!data) {
data = await fetchStrategy.fetcher(fetchStrategy.buildEndpointURL(params), params, {
// burst cache to skip REST API cache when the request is being made under getStaticProps
// if .req is not available then this is a GetStaticPropsContext
burstCache: typeof (ctx as GetServerSidePropsContext).req === 'undefined',
...options.fetchStrategyOptions,
});

if (shouldCache) {
if (debug?.devMode) {
log(LOGTYPE.INFO, `[fetchHookData] cache store for ${cacheKey}`);
}

await cache.set(cacheKey, data, {
ttl: 5 * 60,
});
}
}

if (debug?.devMode) {
log(LOGTYPE.INFO, `[fetchHookData] data.pageInfo for ${key.url}`, data.pageInfo);
Expand All @@ -194,7 +247,7 @@ export async function fetchHookData<T = unknown, P extends EndpointParams = Endp

return {
...normalizedData,
key: serializeKey(key),
key: cacheKey,
isMainQuery: fetchStrategy.isMainQuery(path, params),
additionalCacheObjects: additionalCacheObjects || null,
};
Expand Down
1 change: 0 additions & 1 deletion projects/wp-nextjs/next.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
const { withHeadstartWPConfig } = require('@headstartwp/next/config');

const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
});
Expand Down
7 changes: 6 additions & 1 deletion projects/wp-nextjs/src/pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,12 @@ export async function getStaticProps(context) {
let appSettings;
let slug;
try {
appSettings = await fetchHookData(useAppSettings.fetcher(), context);
appSettings = await fetchHookData(useAppSettings.fetcher(), context, {
cache: {
enabled: true,
},
});

/**
* The static front-page can be set in the WP admin. The default one will be 'front-page'
*/
Expand Down

0 comments on commit ac0bcc0

Please sign in to comment.