Skip to content

Commit f67d456

Browse files
author
Ruslan Matkovskyi
committed
[sitecore-jss-nextjs]: A condition for prefetch requests has been added to improve the performance of redirects.
Additionally, a condition has been added to handle Netlify requests to reduce server load.
1 parent 9585e19 commit f67d456

File tree

2 files changed

+44
-53
lines changed

2 files changed

+44
-53
lines changed

packages/sitecore-jss-nextjs/src/middleware/redirects-middleware.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1383,6 +1383,7 @@ describe('RedirectsMiddleware', () => {
13831383
origin: 'http://localhost:3000',
13841384
clone: cloneUrl,
13851385
},
1386+
headerValues: { 'cdn-loop': 'netlify' },
13861387
},
13871388
});
13881389
setupRedirectStub(301);

packages/sitecore-jss-nextjs/src/middleware/redirects-middleware.ts

+43-53
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { CacheClient, debug, MemoryCacheClient } from '@sitecore-jss/sitecore-jss';
1+
import { debug } from '@sitecore-jss/sitecore-jss';
22
import {
33
GraphQLRedirectsService,
44
GraphQLRedirectsServiceConfig,
@@ -16,6 +16,7 @@ import { MiddlewareBase, MiddlewareBaseConfig } from './middleware';
1616

1717
const REGEXP_CONTEXT_SITE_LANG = new RegExp(/\$siteLang/, 'i');
1818
const REGEXP_ABSOLUTE_URL = new RegExp('^(?:[a-z]+:)?//', 'i');
19+
const NAME_NETLIFY = 'netlify';
1920

2021
type RedirectResult = RedirectInfo & { matchedQueryString?: string };
2122

@@ -37,7 +38,6 @@ export type RedirectsMiddlewareConfig = Omit<GraphQLRedirectsServiceConfig, 'fet
3738
export class RedirectsMiddleware extends MiddlewareBase {
3839
private redirectsService: GraphQLRedirectsService;
3940
private locales: string[];
40-
private cache: CacheClient<RedirectResult | boolean | undefined>;
4141

4242
/**
4343
* @param {RedirectsMiddlewareConfig} [config] redirects middleware config
@@ -49,10 +49,6 @@ export class RedirectsMiddleware extends MiddlewareBase {
4949
// (underlying default 'cross-fetch' is not currently compatible: https://github.com/lquixada/cross-fetch/issues/78)
5050
this.redirectsService = new GraphQLRedirectsService({ ...config, fetch: fetch });
5151
this.locales = config.locales;
52-
this.cache = new MemoryCacheClient<RedirectResult | boolean | undefined>({
53-
cacheEnabled: config.cacheEnabled,
54-
cacheTimeout: config.cacheTimeout,
55-
});
5652
}
5753

5854
/**
@@ -85,15 +81,24 @@ export class RedirectsMiddleware extends MiddlewareBase {
8581
});
8682

8783
const createResponse = async () => {
84+
const response = res || NextResponse.next();
85+
8886
if (this.config.disabled && this.config.disabled(req, res || NextResponse.next())) {
8987
debug.redirects('skipped (redirects middleware is disabled)');
90-
return res || NextResponse.next();
88+
return response;
9189
}
9290

9391
if (this.isPreview(req) || this.excludeRoute(pathname)) {
9492
debug.redirects('skipped (%s)', this.isPreview(req) ? 'preview' : 'route excluded');
9593

96-
return res || NextResponse.next();
94+
return response;
95+
}
96+
97+
// Skip prefetch requests
98+
if (this.isPrefetch(req)) {
99+
debug.redirects('skipped (prefetch)');
100+
response.headers.set('x-middleware-cache', 'no-cache');
101+
return response;
97102
}
98103

99104
site = this.getSite(req, res);
@@ -104,7 +109,7 @@ export class RedirectsMiddleware extends MiddlewareBase {
104109
if (!existsRedirect) {
105110
debug.redirects('skipped (redirect does not exist)');
106111

107-
return res || NextResponse.next();
112+
return response;
108113
}
109114

110115
// Find context site language and replace token
@@ -160,16 +165,16 @@ export class RedirectsMiddleware extends MiddlewareBase {
160165
/** return Response redirect with http code of redirect type */
161166
switch (existsRedirect.redirectType) {
162167
case REDIRECT_TYPE_301: {
163-
return this.createRedirectResponse(url, res, 301, 'Moved Permanently');
168+
return this.createRedirectResponse(url, response, 301, 'Moved Permanently');
164169
}
165170
case REDIRECT_TYPE_302: {
166-
return this.createRedirectResponse(url, res, 302, 'Found');
171+
return this.createRedirectResponse(url, response, 302, 'Found');
167172
}
168173
case REDIRECT_TYPE_SERVER_TRANSFER: {
169-
return this.rewrite(url.href, req, res || NextResponse.next());
174+
return this.rewrite(url.href, req, response);
170175
}
171176
default:
172-
return res || NextResponse.next();
177+
return response;
173178
}
174179
};
175180

@@ -199,29 +204,14 @@ export class RedirectsMiddleware extends MiddlewareBase {
199204
const { pathname: targetURL, search: targetQS = '', locale } = this.normalizeUrl(
200205
req.nextUrl.clone()
201206
);
202-
const cacheKey = `${targetURL}-${targetQS}-${locale}`;
203-
const cachedRedirect = this.cache.getCacheValue(cacheKey);
204-
205-
if (cachedRedirect !== null) {
206-
return typeof cachedRedirect === 'boolean' ? undefined : cachedRedirect;
207-
}
208-
207+
const normalizedPath = targetURL.replace(/\/*$/gi, '');
209208
const redirects = await this.redirectsService.fetchRedirects(siteName);
210-
211209
const language = this.getLanguage(req);
212210
const modifyRedirects = structuredClone(redirects);
211+
let matchedQueryString: string | undefined;
213212

214-
const result = modifyRedirects.length
213+
return modifyRedirects.length
215214
? modifyRedirects.find((redirect: RedirectResult) => {
216-
// generate cache key for the current pattern
217-
const chachedPatternResultKey = `${cacheKey}-${redirect.pattern}-${redirect.target}`;
218-
// Check if the result is already cached
219-
const chachedPatternResult = this.cache.getCacheValue(chachedPatternResultKey);
220-
221-
if (chachedPatternResult !== null) {
222-
return chachedPatternResult;
223-
}
224-
225215
// Modify the redirect pattern to ignore the language prefix in the path
226216
// And escapes non-special "?" characters in a string or regex.
227217
redirect.pattern = this.escapeNonSpecialQuestionMarks(
@@ -260,34 +250,35 @@ export class RedirectsMiddleware extends MiddlewareBase {
260250
* it returns `undefined`. The `matchedQueryString` is later used to indicate whether the query
261251
* string contributed to a successful redirect match.
262252
*/
263-
const matchedQueryString = this.isPermutedQueryMatch({
264-
pathname: targetURL,
265-
queryString: targetQS,
266-
pattern: redirect.pattern,
267-
locale,
268-
});
253+
if (req.headers.get('cdn-loop') === NAME_NETLIFY) {
254+
matchedQueryString = this.getPermutedQueryMatch({
255+
pathname: normalizedPath,
256+
queryString: targetQS,
257+
pattern: redirect.pattern,
258+
locale,
259+
});
260+
} else {
261+
matchedQueryString = [
262+
regexParser(redirect.pattern).test(`${normalizedPath}${targetQS}`),
263+
regexParser(redirect.pattern).test(`/${locale}${normalizedPath}${targetQS}`),
264+
].some(Boolean)
265+
? targetQS
266+
: undefined;
267+
}
269268

270269
// Save the matched query string (if found) into the redirect object
271270
redirect.matchedQueryString = matchedQueryString || '';
272271

273-
const matchedPatterResult =
272+
// Return the redirect if the URL path or any query string permutation matches the pattern
273+
return (
274274
!!(
275275
regexParser(redirect.pattern).test(targetURL) ||
276276
regexParser(redirect.pattern).test(`/${req.nextUrl.locale}${targetURL}`) ||
277277
matchedQueryString
278-
) && (redirect.locale ? redirect.locale.toLowerCase() === locale.toLowerCase() : true);
279-
280-
// Save cache the result for the current pattern
281-
this.cache.setCacheValue(chachedPatternResultKey, matchedPatterResult);
282-
283-
// Return the redirect if the URL path or any query string permutation matches the pattern
284-
return matchedPatterResult;
278+
) && (redirect.locale ? redirect.locale.toLowerCase() === locale.toLowerCase() : true)
279+
);
285280
})
286281
: undefined;
287-
288-
this.cache.setCacheValue(cacheKey, result ? result : undefined);
289-
290-
return result;
291282
}
292283

293284
/**
@@ -372,7 +363,7 @@ export class RedirectsMiddleware extends MiddlewareBase {
372363
* @param {string} [params.locale] - The locale prefix to include in the URL if present.
373364
* @returns {string | undefined} - return query string if any of the query permutations match the provided pattern, undefined otherwise.
374365
*/
375-
private isPermutedQueryMatch({
366+
private getPermutedQueryMatch({
376367
pathname,
377368
queryString,
378369
pattern,
@@ -389,11 +380,10 @@ export class RedirectsMiddleware extends MiddlewareBase {
389380
'?' + permutation.map(([key, value]) => `${key}=${value}`).join('&')
390381
);
391382

392-
const normalizedPath = pathname.replace(/\/*$/gi, '');
393383
return listOfPermuted.find((query: string) =>
394384
[
395-
regexParser(pattern).test(`${normalizedPath}${query}`),
396-
regexParser(pattern).test(`/${locale}${normalizedPath}${query}`),
385+
regexParser(pattern).test(`${pathname}${query}`),
386+
regexParser(pattern).test(`/${locale}${pathname}${query}`),
397387
].some(Boolean)
398388
);
399389
}

0 commit comments

Comments
 (0)