Skip to content

Commit 0ced0b1

Browse files
committed
fix(astro): Construct parametrized route during runtime (#17190)
For v9, the changes were already reverted in this PR (#17179) to create a quick fix we can release soon. However, this removed some parametrization. This PR here not only fixed the problem with continuously writing to `globalThis` to share build-time data with the runtime (we don't do this anymore). The route parametrization now happens only during runtime, as we have access to the route segments at runtime with Astro v5. This adds a **little** performance overhead when compared with the previous approach (the route segments are now constructed during runtime) - but this is not an expensive operation. The `.find` method was used in the previous approach as well. Fixes #17179
1 parent 2398fc0 commit 0ced0b1

File tree

1 file changed

+29
-7
lines changed

1 file changed

+29
-7
lines changed

packages/astro/src/server/middleware.ts

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ import {
2222
startSpan,
2323
withIsolationScope,
2424
} from '@sentry/node';
25-
import type { APIContext, MiddlewareResponseHandler } from 'astro';
26-
import type { ResolvedRouteWithCasedPattern } from '../integration/types';
25+
import type { APIContext, MiddlewareResponseHandler, RoutePart } from 'astro';
2726

2827
type MiddlewareOptions = {
2928
/**
@@ -96,9 +95,6 @@ async function instrumentRequest(
9695
addNonEnumerableProperty(locals, '__sentry_wrapped__', true);
9796
}
9897

99-
const storedBuildTimeRoutes = (globalThis as unknown as { __sentryRouteInfo?: ResolvedRouteWithCasedPattern[] })
100-
?.__sentryRouteInfo;
101-
10298
const isDynamicPageRequest = checkIsDynamicPageRequest(ctx);
10399

104100
const request = ctx.request;
@@ -135,10 +131,21 @@ async function instrumentRequest(
135131
// `routePattern` is available after Astro 5
136132
const contextWithRoutePattern = ctx as Parameters<MiddlewareResponseHandler>[0] & { routePattern?: string };
137133
const rawRoutePattern = contextWithRoutePattern.routePattern;
138-
const foundRoute = storedBuildTimeRoutes?.find(route => route.pattern === rawRoutePattern);
134+
135+
// @ts-expect-error Implicit any on Symbol.for (This is available in Astro 5)
136+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
137+
const routesFromManifest = ctx?.[Symbol.for('context.routes')]?.manifest?.routes;
138+
139+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
140+
const matchedRouteSegmentsFromManifest = routesFromManifest?.find(
141+
(route: { routeData?: { route?: string } }) => route?.routeData?.route === rawRoutePattern,
142+
)?.routeData?.segments;
139143

140144
const parametrizedRoute =
141-
foundRoute?.patternCaseSensitive || interpolateRouteFromUrlAndParams(ctx.url.pathname, ctx.params);
145+
// Astro v5 - Joining the segments to get the correct casing of the parametrized route
146+
(matchedRouteSegmentsFromManifest && joinRouteSegments(matchedRouteSegmentsFromManifest)) ||
147+
// Fallback (Astro v4 and earlier)
148+
interpolateRouteFromUrlAndParams(ctx.url.pathname, ctx.params);
142149

143150
const source = parametrizedRoute ? 'route' : 'url';
144151
// storing res in a variable instead of directly returning is necessary to
@@ -365,3 +372,18 @@ function checkIsDynamicPageRequest(context: Parameters<MiddlewareResponseHandler
365372
return false;
366373
}
367374
}
375+
376+
/**
377+
* Join Astro route segments into a case-sensitive single path string.
378+
*
379+
* Astro lowercases the parametrized route. Joining segments manually is recommended to get the correct casing of the routes.
380+
* Recommendation in comment: https://github.com/withastro/astro/issues/13885#issuecomment-2934203029
381+
* Function Reference: https://github.com/joanrieu/astro-typed-links/blob/b3dc12c6fe8d672a2bc2ae2ccc57c8071bbd09fa/package/src/integration.ts#L16
382+
*/
383+
function joinRouteSegments(segments: RoutePart[][]): string {
384+
const parthArray = segments.map(segment =>
385+
segment.map(routePart => (routePart.dynamic ? `[${routePart.content}]` : routePart.content)).join(''),
386+
);
387+
388+
return `/${parthArray.join('/')}`;
389+
}

0 commit comments

Comments
 (0)