From c31379afbec52519d451335d89a72614e59aa5ef Mon Sep 17 00:00:00 2001 From: Jared Stowell Date: Sat, 7 Mar 2026 10:47:45 -0600 Subject: [PATCH] fix(routing): keep static routes ahead of dynamic infix routes --- packages/vinext/src/routing/utils.ts | 6 ++++++ tests/routing.test.ts | 11 +++++++++++ 2 files changed, 17 insertions(+) diff --git a/packages/vinext/src/routing/utils.ts b/packages/vinext/src/routing/utils.ts index 0ec4041c..8c55e258 100644 --- a/packages/vinext/src/routing/utils.ts +++ b/packages/vinext/src/routing/utils.ts @@ -67,5 +67,11 @@ export function routePrecedence(pattern: string): number { score -= staticPrefixCount * 50; } + // Keep all dynamic routes below purely static routes. + // Static routes always score 0, so dynamic scores must stay positive. + if (isDynamic && score <= 0) { + score = 1; + } + return score; } diff --git a/tests/routing.test.ts b/tests/routing.test.ts index 71a9ffb2..241bacde 100644 --- a/tests/routing.test.ts +++ b/tests/routing.test.ts @@ -2,12 +2,23 @@ import { describe, it, expect } from "vitest"; import path from "node:path"; import { pagesRouter, matchRoute } from "../packages/vinext/src/routing/pages-router.js"; import { appRouter, matchAppRoute, invalidateAppRouteCache } from "../packages/vinext/src/routing/app-router.js"; +import { routePrecedence } from "../packages/vinext/src/routing/utils.js"; const FIXTURE_DIR = path.resolve( import.meta.dirname, "./fixtures/pages-basic/pages", ); +describe("routePrecedence", () => { + it("keeps fully static routes ahead of dynamic routes with static suffixes", () => { + const staticScore = routePrecedence("/users/settings"); + const dynamicWithSuffixScore = routePrecedence("/:id/settings"); + + expect(staticScore).toBe(0); + expect(dynamicWithSuffixScore).toBeGreaterThan(staticScore); + }); +}); + describe("pagesRouter - route discovery", () => { it("discovers pages from the fixture directory", async () => { const routes = await pagesRouter(FIXTURE_DIR);