Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feat(isr): add custom cache key generation logic #1771

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libs/isr/models/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export {
VariantRebuildItem,
} from './cache-handler';
export {
CacheKeyGeneratorFn,
InvalidateConfig,
ISRHandlerConfig,
ModifyHtmlCallbackFn,
Expand Down
11 changes: 11 additions & 0 deletions libs/isr/models/src/isr-handler-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ export interface ISRHandlerConfig {
* If set to true, the server will provide the cached HTML as soon as possible and will revalidate the cache in the background.
*/
backgroundRevalidation?: boolean;

/**
* This callback lets you use custom cache key generation logic. If not provided, it will use the default cache key generation logic.
*/
cacheKeyGenerator?: CacheKeyGeneratorFn;
}

export interface ServeFromCacheConfig {
Expand All @@ -144,6 +149,12 @@ export interface InvalidateConfig {
providers?: Provider[];
}

export type CacheKeyGeneratorFn = (
url: string,
allowedQueryParams: string[] | null | undefined,
variant: RenderVariant | null,
) => string;

export type ModifyHtmlCallbackFn = (
req: Request,
html: string,
Expand Down
25 changes: 21 additions & 4 deletions libs/isr/server/src/cache-generation.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { Provider } from '@angular/core';
import { CacheHandler, ISRHandlerConfig } from '@rx-angular/isr/models';
import {
CacheHandler,
CacheKeyGeneratorFn,
ISRHandlerConfig,
RenderVariant,
} from '@rx-angular/isr/models';
import { Request, Response } from 'express';
import { ISRLogger } from './isr-logger';
import { defaultModifyGeneratedHtml } from './modify-generated-html';
import { getCacheKey, getVariant } from './utils/cache-utils';
import { defaultCacheKeyGenerator, getVariant } from './utils/cache-utils';
import { getRouteISRDataFromHTML } from './utils/get-isr-options';
import { renderUrl, RenderUrlConfig } from './utils/render-url';

Expand All @@ -21,7 +26,19 @@ export class CacheGeneration {
public isrConfig: ISRHandlerConfig,
public cache: CacheHandler,
public logger: ISRLogger,
) {}
) {
if (!this.isrConfig.cacheKeyGenerator) {
this.isrConfig.cacheKeyGenerator = defaultCacheKeyGenerator;
}
}
getCacheKey: CacheKeyGeneratorFn = (
url: string,
allowedQueryParams: string[] | null | undefined,
variant: RenderVariant | null,
) => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return this.isrConfig.cacheKeyGenerator!(url, allowedQueryParams, variant);
};

async generate(
req: Request,
Expand All @@ -31,7 +48,7 @@ export class CacheGeneration {
): Promise<IGeneratedResult | void> {
const { url } = req;
const variant = getVariant(req, this.isrConfig.variants);
const cacheKey = getCacheKey(
const cacheKey = this.getCacheKey(
url,
this.isrConfig.allowedQueryParams,
variant,
Expand Down
6 changes: 3 additions & 3 deletions libs/isr/server/src/isr-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { NextFunction, Request, Response } from 'express';
import { CacheGeneration } from './cache-generation';
import { InMemoryCacheHandler } from './cache-handlers/in-memory-cache-handler';
import { ISRLogger } from './isr-logger';
import { getCacheKey, getVariant } from './utils/cache-utils';
import { getVariant } from './utils/cache-utils';

export class ISRHandler {
protected cache!: CacheHandler;
Expand Down Expand Up @@ -148,7 +148,7 @@ export class ISRHandler {
for (const variant of variants) {
result.push({
url,
cacheKey: getCacheKey(
cacheKey: this.cacheGeneration.getCacheKey(
url,
this.isrConfig.allowedQueryParams,
variant,
Expand All @@ -171,7 +171,7 @@ export class ISRHandler {
): Promise<Response | void> {
try {
const variant = getVariant(req, this.isrConfig.variants);
const cacheKey = getCacheKey(
const cacheKey = this.cacheGeneration.getCacheKey(
req.url,
this.isrConfig.allowedQueryParams,
variant,
Expand Down
12 changes: 6 additions & 6 deletions libs/isr/server/src/utils/cache-utils.spec.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
import { RenderVariant } from '../../../models/src';
import { getCacheKey } from './cache-utils';
import { defaultCacheKeyGenerator } from './cache-utils';

describe('getCacheKey', () => {
it('should return the URL without query parameters when none are allowed', () => {
const url = '/page?param1=value1&param2=value2';
const result = getCacheKey(url, [], null);
const result = defaultCacheKeyGenerator(url, [], null);
expect(result).toBe('/page');
});

it('should return the URL with query parameters when it is null or undefined', () => {
const url = '/page?param1=value1&param2=value2';
const result = getCacheKey(url, null, null);
const result = defaultCacheKeyGenerator(url, null, null);
expect(result).toBe('/page?param1=value1&param2=value2');
});

it('should include only allowed query parameters in the result', () => {
const url = '/page?allowed=value&disallowed=value';
const result = getCacheKey(url, ['allowed'], null);
const result = defaultCacheKeyGenerator(url, ['allowed'], null);
expect(result).toBe('/page?allowed=value');
});

it('should exclude disallowed query parameters', () => {
const url = '/page?allowed=value&disallowed=value';
const result = getCacheKey(url, ['allowed'], null);
const result = defaultCacheKeyGenerator(url, ['allowed'], null);
expect(result).not.toContain('disallowed=value');
});

Expand All @@ -32,7 +32,7 @@ describe('getCacheKey', () => {
identifier: 'variant123',
detectVariant: () => true,
};
const result = getCacheKey(url, ['param'], variant);
const result = defaultCacheKeyGenerator(url, ['param'], variant);
expect(result).toBe('/page?param=value<variantId:variant123>');
});
});
2 changes: 1 addition & 1 deletion libs/isr/server/src/utils/cache-utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { RenderVariant } from '@rx-angular/isr/models';
import { Request } from 'express';

export const getCacheKey = (
export const defaultCacheKeyGenerator = (
url: string,
allowedQueryParams: string[] | null | undefined,
variant: RenderVariant | null,
Expand Down
Loading