From 9112114560ea331a71fa6612ccea1e86f38de5ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=B3=C3=B0i=20Karlsson?= Date: Sat, 5 Jul 2025 01:43:25 +0200 Subject: [PATCH 1/4] fix: resolve route file outside of app dir relative to app dir --- .changeset/red-pugs-itch.md | 5 +++++ .../__tests__/flatRoutes-test.ts | 10 ++++++++++ packages/react-router-fs-routes/flatRoutes.ts | 2 +- 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 .changeset/red-pugs-itch.md diff --git a/.changeset/red-pugs-itch.md b/.changeset/red-pugs-itch.md new file mode 100644 index 0000000000..39fd463d92 --- /dev/null +++ b/.changeset/red-pugs-itch.md @@ -0,0 +1,5 @@ +--- +"@react-router/fs-routes": patch +--- + +Resolve route file outside of app directory relative to app directory diff --git a/packages/react-router-fs-routes/__tests__/flatRoutes-test.ts b/packages/react-router-fs-routes/__tests__/flatRoutes-test.ts index 5e7b2e8e1d..638296e764 100644 --- a/packages/react-router-fs-routes/__tests__/flatRoutes-test.ts +++ b/packages/react-router-fs-routes/__tests__/flatRoutes-test.ts @@ -912,4 +912,14 @@ describe("flatRoutes", () => { ); }); }); + + test("should include a valid file for a route outside of the app directory", () => { + const routesDir = path.join("test", "root", "routes"); + const routeFile = path.join(routesDir, "route.tsx"); + + const manifest = flatRoutesUniversal(APP_DIR, [routeFile]); + const routeInfo = manifest[path.relative(APP_DIR, routesDir)]; + expect(routeInfo).toBeDefined(); + expect(routeInfo.file).toBe(path.relative(APP_DIR, routeFile)); + }); }); diff --git a/packages/react-router-fs-routes/flatRoutes.ts b/packages/react-router-fs-routes/flatRoutes.ts index 63265f84d1..c322ba3433 100644 --- a/packages/react-router-fs-routes/flatRoutes.ts +++ b/packages/react-router-fs-routes/flatRoutes.ts @@ -174,7 +174,7 @@ export function flatRoutesUniversal( let pathname = createRoutePath(segments, raw, index); routeManifest[routeId] = { - file: file.slice(appDirectory.length + 1), + file: path.relative(appDirectory, file), id: routeId, path: pathname, }; From 0398da0312c3ea1b97cb15470bb0e74e03c3df95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=B3=C3=B0i=20Karlsson?= Date: Sat, 5 Jul 2025 01:59:59 +0200 Subject: [PATCH 2/4] fix: posix and normalizedApp --- packages/react-router-fs-routes/flatRoutes.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/react-router-fs-routes/flatRoutes.ts b/packages/react-router-fs-routes/flatRoutes.ts index c322ba3433..49c015bf39 100644 --- a/packages/react-router-fs-routes/flatRoutes.ts +++ b/packages/react-router-fs-routes/flatRoutes.ts @@ -134,6 +134,8 @@ export function flatRoutesUniversal( let prefixLookup = new PrefixLookupTrie(); let uniqueRoutes = new Map(); let routeIdConflicts = new Map(); + let normalizedApp = normalizeSlashes(appDirectory); + let appWithPrefix = path.posix.join(normalizedApp, prefix); // id -> file let routeIds = new Map(); @@ -142,9 +144,8 @@ export function flatRoutesUniversal( let normalizedFile = normalizeSlashes(file); let routeExt = path.extname(normalizedFile); let routeDir = path.dirname(normalizedFile); - let normalizedApp = normalizeSlashes(appDirectory); let routeId = - routeDir === path.posix.join(normalizedApp, prefix) + routeDir === appWithPrefix ? path.posix .relative(normalizedApp, normalizedFile) .slice(0, -routeExt.length) @@ -174,7 +175,7 @@ export function flatRoutesUniversal( let pathname = createRoutePath(segments, raw, index); routeManifest[routeId] = { - file: path.relative(appDirectory, file), + file: path.posix.relative(normalizedApp, file), id: routeId, path: pathname, }; From 19d5123dedfeb8de025f22ae4443cb591b7eeb08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=B3=C3=B0i=20Karlsson?= Date: Sat, 5 Jul 2025 02:26:39 +0200 Subject: [PATCH 3/4] fix: better structured tests with posix --- .../__tests__/flatRoutes-test.ts | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/packages/react-router-fs-routes/__tests__/flatRoutes-test.ts b/packages/react-router-fs-routes/__tests__/flatRoutes-test.ts index 638296e764..787fe6dedc 100644 --- a/packages/react-router-fs-routes/__tests__/flatRoutes-test.ts +++ b/packages/react-router-fs-routes/__tests__/flatRoutes-test.ts @@ -913,13 +913,26 @@ describe("flatRoutes", () => { }); }); - test("should include a valid file for a route outside of the app directory", () => { - const routesDir = path.join("test", "root", "routes"); - const routeFile = path.join(routesDir, "route.tsx"); - - const manifest = flatRoutesUniversal(APP_DIR, [routeFile]); - const routeInfo = manifest[path.relative(APP_DIR, routesDir)]; - expect(routeInfo).toBeDefined(); - expect(routeInfo.file).toBe(path.relative(APP_DIR, routeFile)); + describe("generates route manifest entry files relative to the app directory", () => { + let testCases: [string, string][] = [ + [path.posix.join(APP_DIR, "routes"), "routes"], + [ + path.posix.join(APP_DIR, "..", "routes"), + path.posix.join("..", "routes"), + ], + ]; + + let fileName = "route.tsx"; + + testCases.forEach(([routesDir, expected]) => { + test(`for routes directory "${routesDir}"`, () => { + const routeFile = path.join(routesDir, fileName); + const routeInfo = flatRoutesUniversal(APP_DIR, [routeFile]); + const routes = Object.values(routeInfo); + + expect(routes).toHaveLength(1); + expect(routes[0].file).toBe(path.posix.join(expected, fileName)); + }); + }); }); }); From f18e2807fd75a16782bfa2e870256fd971394190 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=B3=C3=B0i=20Karlsson?= Date: Sat, 5 Jul 2025 09:39:38 +0200 Subject: [PATCH 4/4] fix: misaligned muscle memory --- .../react-router-fs-routes/__tests__/flatRoutes-test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/react-router-fs-routes/__tests__/flatRoutes-test.ts b/packages/react-router-fs-routes/__tests__/flatRoutes-test.ts index 787fe6dedc..4ce23adc02 100644 --- a/packages/react-router-fs-routes/__tests__/flatRoutes-test.ts +++ b/packages/react-router-fs-routes/__tests__/flatRoutes-test.ts @@ -926,9 +926,9 @@ describe("flatRoutes", () => { testCases.forEach(([routesDir, expected]) => { test(`for routes directory "${routesDir}"`, () => { - const routeFile = path.join(routesDir, fileName); - const routeInfo = flatRoutesUniversal(APP_DIR, [routeFile]); - const routes = Object.values(routeInfo); + let routeFile = path.posix.join(routesDir, fileName); + let routeInfo = flatRoutesUniversal(APP_DIR, [routeFile]); + let routes = Object.values(routeInfo); expect(routes).toHaveLength(1); expect(routes[0].file).toBe(path.posix.join(expected, fileName));