Skip to content
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
8 changes: 5 additions & 3 deletions packages/nextjs/src/client/routing/isrRoutingTracing.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { LRUMap } from '@sentry/core';
import { WINDOW } from '@sentry/react';
import { getManifest, maybeParameterizeRoute } from './parameterization';

/**
* Cache for ISR/SSG route checks. Exported for testing purposes.
* @internal
*/
export const IS_ISR_SSG_ROUTE_CACHE = new Map<string, boolean>();
export const IS_ISR_SSG_ROUTE_CACHE = new LRUMap<string, boolean>(100);

/**
* Check if the current page is an ISR/SSG route by checking the route manifest.
Expand All @@ -17,8 +18,9 @@ export function isIsrSsgRoute(pathname: string): boolean {
const pathToCheck = parameterizedPath || pathname;

// Check cache using the parameterized path as the key
if (IS_ISR_SSG_ROUTE_CACHE.has(pathToCheck)) {
return IS_ISR_SSG_ROUTE_CACHE.get(pathToCheck) as boolean;
const cachedResult = IS_ISR_SSG_ROUTE_CACHE.get(pathToCheck);
if (cachedResult !== undefined) {
return cachedResult;
}

// Cache miss get the manifest
Expand Down
22 changes: 11 additions & 11 deletions packages/nextjs/test/client/isrRoutingTracing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -301,14 +301,14 @@ describe('isrRoutingTracing', () => {
const result1 = isIsrSsgRoute('/products/123');
expect(result1).toBe(true);
expect(IS_ISR_SSG_ROUTE_CACHE.size).toBe(1);
expect(IS_ISR_SSG_ROUTE_CACHE.has('/products/:id')).toBe(true);
expect(IS_ISR_SSG_ROUTE_CACHE.get('/products/:id')).toBeDefined();

// Second call with different concrete path /products/456
const result2 = isIsrSsgRoute('/products/456');
expect(result2).toBe(true);
// Cache size should still be 1 - both paths map to same parameterized route
expect(IS_ISR_SSG_ROUTE_CACHE.size).toBe(1);
expect(IS_ISR_SSG_ROUTE_CACHE.has('/products/:id')).toBe(true);
expect(IS_ISR_SSG_ROUTE_CACHE.get('/products/:id')).toBeDefined();

// Third call with yet another path /products/999
const result3 = isIsrSsgRoute('/products/999');
Expand All @@ -324,7 +324,7 @@ describe('isrRoutingTracing', () => {
// First call - cache miss, will populate cache
isIsrSsgRoute('/products/1');
expect(IS_ISR_SSG_ROUTE_CACHE.size).toBe(1);
expect(IS_ISR_SSG_ROUTE_CACHE.has('/products/:id')).toBe(true);
expect(IS_ISR_SSG_ROUTE_CACHE.get('/products/:id')).toBeDefined();

// Second call with different concrete path - cache hit
const result2 = isIsrSsgRoute('/products/2');
Expand All @@ -341,7 +341,7 @@ describe('isrRoutingTracing', () => {
it('should cache false results for non-ISR routes', () => {
const result1 = isIsrSsgRoute('/not-an-isr-route');
expect(result1).toBe(false);
expect(IS_ISR_SSG_ROUTE_CACHE.has('/not-an-isr-route')).toBe(true);
expect(IS_ISR_SSG_ROUTE_CACHE.get('/not-an-isr-route')).toBeDefined();
expect(IS_ISR_SSG_ROUTE_CACHE.get('/not-an-isr-route')).toBe(false);

// Second call should use cache
Expand All @@ -355,14 +355,14 @@ describe('isrRoutingTracing', () => {

const result = isIsrSsgRoute('/any-route');
expect(result).toBe(false);
expect(IS_ISR_SSG_ROUTE_CACHE.has('/any-route')).toBe(true);
expect(IS_ISR_SSG_ROUTE_CACHE.get('/any-route')).toBeDefined();
expect(IS_ISR_SSG_ROUTE_CACHE.get('/any-route')).toBe(false);
});

it('should cache static routes without parameterization', () => {
const result1 = isIsrSsgRoute('/blog');
expect(result1).toBe(true);
expect(IS_ISR_SSG_ROUTE_CACHE.has('/blog')).toBe(true);
expect(IS_ISR_SSG_ROUTE_CACHE.get('/blog')).toBeDefined();

// Second call should use cache
const result2 = isIsrSsgRoute('/blog');
Expand All @@ -378,10 +378,10 @@ describe('isrRoutingTracing', () => {

// Should have 4 cache entries (one for each unique route pattern)
expect(IS_ISR_SSG_ROUTE_CACHE.size).toBe(4);
expect(IS_ISR_SSG_ROUTE_CACHE.has('/products/:id')).toBe(true);
expect(IS_ISR_SSG_ROUTE_CACHE.has('/posts/:slug')).toBe(true);
expect(IS_ISR_SSG_ROUTE_CACHE.has('/blog')).toBe(true);
expect(IS_ISR_SSG_ROUTE_CACHE.has('/')).toBe(true);
expect(IS_ISR_SSG_ROUTE_CACHE.get('/products/:id')).toBeDefined();
expect(IS_ISR_SSG_ROUTE_CACHE.get('/posts/:slug')).toBeDefined();
expect(IS_ISR_SSG_ROUTE_CACHE.get('/blog')).toBeDefined();
expect(IS_ISR_SSG_ROUTE_CACHE.get('/')).toBeDefined();
});

it('should efficiently handle multiple calls to same dynamic route with different params', () => {
Expand All @@ -392,7 +392,7 @@ describe('isrRoutingTracing', () => {

// Should only have 1 cache entry despite 100 calls
expect(IS_ISR_SSG_ROUTE_CACHE.size).toBe(1);
expect(IS_ISR_SSG_ROUTE_CACHE.has('/products/:id')).toBe(true);
expect(IS_ISR_SSG_ROUTE_CACHE.get('/products/:id')).toBeDefined();
});
});
});
Loading