diff --git a/.changeset/sweet-spoons-cheer.md b/.changeset/sweet-spoons-cheer.md new file mode 100644 index 000000000000..48060f063893 --- /dev/null +++ b/.changeset/sweet-spoons-cheer.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Dynamic route params should ignore param order when matching paths diff --git a/packages/astro/src/core/render/core.ts b/packages/astro/src/core/render/core.ts index aff319257a31..7ff17de70c26 100644 --- a/packages/astro/src/core/render/core.ts +++ b/packages/astro/src/core/render/core.ts @@ -33,8 +33,7 @@ async function getParamsAndProps(opts: GetParamsAndPropsOptions): Promise<[Param routeCacheEntry = await callGetStaticPaths(mod, route, true, logging); routeCache.set(route, routeCacheEntry); } - const paramsKey = JSON.stringify(params); - const matchedStaticPath = findPathItemByKey(routeCacheEntry.staticPaths, paramsKey); + const matchedStaticPath = findPathItemByKey(routeCacheEntry.staticPaths, params); if (!matchedStaticPath) { throw new Error(`[getStaticPaths] route pattern matched, but no matching static path found. (${pathname})`); } diff --git a/packages/astro/src/core/render/route-cache.ts b/packages/astro/src/core/render/route-cache.ts index 889c64a48a8a..43f41717e133 100644 --- a/packages/astro/src/core/render/route-cache.ts +++ b/packages/astro/src/core/render/route-cache.ts @@ -1,4 +1,4 @@ -import type { ComponentInstance, GetStaticPathsItem, GetStaticPathsResult, GetStaticPathsResultKeyed, RouteData, RSS } from '../../@types/astro'; +import type { ComponentInstance, GetStaticPathsItem, GetStaticPathsResult, GetStaticPathsResultKeyed, Params, RouteData, RSS } from '../../@types/astro'; import { LogOptions, warn, debug } from '../logger.js'; import { generatePaginateFunction } from './paginate.js'; @@ -6,6 +6,11 @@ import { validateGetStaticPathsModule, validateGetStaticPathsResult } from '../r type RSSFn = (...args: any[]) => any; +function stringifyParams(params: Params) { + // Always sort keys before stringifying to make sure objects match regardless of parameter ordering + return JSON.stringify(params, Object.keys(params).sort()); +} + export async function callGetStaticPaths(mod: ComponentInstance, route: RouteData, isValidate: boolean, logging: LogOptions): Promise { validateGetStaticPathsModule(mod); const resultInProgress = { @@ -23,7 +28,7 @@ export async function callGetStaticPaths(mod: ComponentInstance, route: RouteDat const keyedStaticPaths = staticPaths as GetStaticPathsResultKeyed; keyedStaticPaths.keyed = new Map(); for (const sp of keyedStaticPaths) { - const paramsKey = JSON.stringify(sp.params); + const paramsKey = stringifyParams(sp.params); keyedStaticPaths.keyed.set(paramsKey, sp); } if (isValidate) { @@ -73,7 +78,8 @@ export class RouteCache { } } -export function findPathItemByKey(staticPaths: GetStaticPathsResultKeyed, paramsKey: string) { +export function findPathItemByKey(staticPaths: GetStaticPathsResultKeyed, params: Params) { + const paramsKey = stringifyParams(params); let matchedStaticPath = staticPaths.keyed.get(paramsKey); if (matchedStaticPath) { return matchedStaticPath; diff --git a/packages/astro/test/fixtures/astro-get-static-paths/src/pages/blog/[year]/[slug].astro b/packages/astro/test/fixtures/astro-get-static-paths/src/pages/blog/[year]/[slug].astro new file mode 100644 index 000000000000..b5c8ec282e25 --- /dev/null +++ b/packages/astro/test/fixtures/astro-get-static-paths/src/pages/blog/[year]/[slug].astro @@ -0,0 +1,17 @@ +--- +export async function getStaticPaths() { + return [ + { params: { year: '2022', slug: 'post-1' } }, + { params: { slug: 'post-2', year: '2022' } }, + ] +} + +const { year, slug } = Astro.request.params +--- + + + + {year} | {slug} + + + \ No newline at end of file