diff --git a/packages/remix/src/config/createRemixRouteManifest.ts b/packages/remix/src/config/createRemixRouteManifest.ts index b954061f4816..ed0f394e5d66 100644 --- a/packages/remix/src/config/createRemixRouteManifest.ts +++ b/packages/remix/src/config/createRemixRouteManifest.ts @@ -27,7 +27,7 @@ function isRouteFile(filename: string): boolean { * Convert Remix route file paths to parameterized paths at build time. * * Examples: - * - index.tsx -> / + * - _index.tsx -> / * - users.tsx -> /users * - users.$id.tsx -> /users/:id * - users.$id.posts.$postId.tsx -> /users/:id/posts/:postId @@ -35,7 +35,7 @@ function isRouteFile(filename: string): boolean { * - docs.$.tsx -> /docs/:* * - users/$id.tsx (nested folder) -> /users/:id * - users/$id/posts.tsx (nested folder) -> /users/:id/posts - * - users/index.tsx (nested folder) -> /users + * - users/_index.tsx (nested folder) -> /users * - _layout.tsx -> null (pathless layout route, not URL-addressable) * - _auth.tsx -> null (pathless layout route, not URL-addressable) * @@ -48,7 +48,7 @@ export function convertRemixRouteToPath(filename: string): { path: string; isDyn const basename = filename.replace(/\.(tsx?|jsx?)$/, ''); // Handle root index route - if (basename === 'index' || basename === '_index') { + if (basename === '_index') { return { path: '/', isDynamic: false }; } @@ -75,13 +75,6 @@ export function convertRemixRouteToPath(filename: string): { path: string; isDyn continue; } - // Handle 'index' segments at the end (skip only if there are path segments, - // otherwise root index is handled by the early return above) - if (segment === 'index' && i === segments.length - 1 && pathSegments.length > 0) { - isIndexRoute = true; - continue; - } - if (segment === '$') { pathSegments.push(':*'); isDynamic = true; @@ -92,7 +85,7 @@ export function convertRemixRouteToPath(filename: string): { path: string; isDyn const paramName = segment.substring(1); pathSegments.push(`:${paramName}`); isDynamic = true; - } else if (segment !== 'index') { + } else { pathSegments.push(segment); } } diff --git a/packages/remix/src/server/instrumentServer.ts b/packages/remix/src/server/instrumentServer.ts index c4eb4ed7e420..192bdb80cfb2 100644 --- a/packages/remix/src/server/instrumentServer.ts +++ b/packages/remix/src/server/instrumentServer.ts @@ -510,7 +510,7 @@ export const makeWrappedCreateRequestHandler = (options?: { instrumentTracing?: /** * Monkey-patch Remix's `createRequestHandler` from `@remix-run/server-runtime` - * which Remix Adapters (https://remix.run/docs/en/v1/api/remix) use underneath. + * which Remix Adapters (https://remix.run/docs/en/main/other-api/adapter) use underneath. */ export function instrumentServer(options?: { instrumentTracing?: boolean }): void { const pkg = loadModule<{ diff --git a/packages/remix/src/utils/utils.ts b/packages/remix/src/utils/utils.ts index 2e9fa21687bc..458c1b19cfcd 100644 --- a/packages/remix/src/utils/utils.ts +++ b/packages/remix/src/utils/utils.ts @@ -3,7 +3,7 @@ import type { AgnosticRouteObject } from '@remix-run/router'; import type { Span, TransactionSource } from '@sentry/core'; import { debug } from '@sentry/core'; import { DEBUG_BUILD } from './debug-build'; -import { getRequestMatch, matchServerRoutes } from './vendor/response'; +import { matchServerRoutes } from './vendor/response'; type ServerRouteManifest = ServerBuild['routes']; @@ -56,7 +56,7 @@ export function convertRemixRouteIdToPath(routeId: string): string { const path = routeId.replace(/^routes\//, ''); // Handle root index route - if (path === 'index' || path === '_index') { + if (path === '_index') { return '/'; } @@ -81,12 +81,6 @@ export function convertRemixRouteIdToPath(routeId: string): string { continue; } - // Handle 'index' segments at the end (skip only if there are path segments, - // otherwise root index is handled by the early return above) - if (segment === 'index' && i === segments.length - 1 && pathSegments.length > 0) { - continue; - } - // Handle splat routes (catch-all) // Remix accesses splat params via params["*"] at runtime if (segment === '$') { @@ -98,8 +92,7 @@ export function convertRemixRouteIdToPath(routeId: string): string { if (segment.startsWith('$')) { const paramName = segment.substring(1); pathSegments.push(`:${paramName}`); - } else if (segment !== 'index') { - // Static segment (skip remaining 'index' segments) + } else { pathSegments.push(segment); } } @@ -120,9 +113,9 @@ export function isCloudflareEnv(): boolean { */ export function getTransactionName(routes: AgnosticRouteObject[], url: URL): [string, TransactionSource] { const matches = matchServerRoutes(routes, url.pathname); - const match = matches && getRequestMatch(url, matches); + const match = matches?.[matches.length - 1]; - if (match === null) { + if (!match) { return [url.pathname, 'url']; } diff --git a/packages/remix/src/utils/vendor/response.ts b/packages/remix/src/utils/vendor/response.ts index 71c937ba96a2..bf3ee01ef66a 100644 --- a/packages/remix/src/utils/vendor/response.ts +++ b/packages/remix/src/utils/vendor/response.ts @@ -85,37 +85,3 @@ export function matchServerRoutes( pathnameBase: match.pathnameBase, })); } - -/** - * https://github.com/remix-run/remix/blob/97999d02493e8114c39d48b76944069d58526e8d/packages/remix-server-runtime/server.ts#L573-L586 - */ -export function isIndexRequestUrl(url: URL): boolean { - for (const param of url.searchParams.getAll('index')) { - // only use bare `?index` params without a value - // ✅ /foo?index - // ✅ /foo?index&index=123 - // ✅ /foo?index=123&index - // ❌ /foo?index=123 - if (param === '') { - return true; - } - } - - return false; -} - -/** - * https://github.com/remix-run/remix/blob/97999d02493e8114c39d48b76944069d58526e8d/packages/remix-server-runtime/server.ts#L588-L596 - */ -export function getRequestMatch( - url: URL, - matches: AgnosticRouteMatch[], -): AgnosticRouteMatch { - const match = matches.slice(-1)[0] as AgnosticRouteMatch; - - if (!isIndexRequestUrl(url) && match.route.id?.endsWith('/index')) { - return matches.slice(-2)[0] as AgnosticRouteMatch; - } - - return match; -} diff --git a/packages/remix/test/config/manifest/createRemixRouteManifest.test.ts b/packages/remix/test/config/manifest/createRemixRouteManifest.test.ts index bdc1a4c5811e..ccf968e87ca3 100644 --- a/packages/remix/test/config/manifest/createRemixRouteManifest.test.ts +++ b/packages/remix/test/config/manifest/createRemixRouteManifest.test.ts @@ -30,7 +30,7 @@ describe('createRemixRouteManifest', () => { const { tempDir, routesDir } = createTestDir(); // Create test route files - fs.writeFileSync(path.join(routesDir, 'index.tsx'), '// index route'); + fs.writeFileSync(path.join(routesDir, '_index.tsx'), '// index route'); fs.writeFileSync(path.join(routesDir, 'about.tsx'), '// about route'); fs.writeFileSync(path.join(routesDir, 'users.$id.tsx'), '// users dynamic route'); @@ -48,7 +48,7 @@ describe('createRemixRouteManifest', () => { }); // Clean up - fs.unlinkSync(path.join(routesDir, 'index.tsx')); + fs.unlinkSync(path.join(routesDir, '_index.tsx')); fs.unlinkSync(path.join(routesDir, 'about.tsx')); fs.unlinkSync(path.join(routesDir, 'users.$id.tsx')); }); @@ -60,9 +60,9 @@ describe('createRemixRouteManifest', () => { const usersDir = path.join(routesDir, 'users'); fs.mkdirSync(usersDir, { recursive: true }); - fs.writeFileSync(path.join(routesDir, 'index.tsx'), '// root index'); + fs.writeFileSync(path.join(routesDir, '_index.tsx'), '// root index'); fs.writeFileSync(path.join(usersDir, '$id.tsx'), '// user id'); - fs.writeFileSync(path.join(usersDir, 'index.tsx'), '// users index'); + fs.writeFileSync(path.join(usersDir, '_index.tsx'), '// users index'); const manifest = createRemixRouteManifest({ rootDir: tempDir }); @@ -86,12 +86,12 @@ describe('createRemixRouteManifest', () => { fs.mkdirSync(postsDir, { recursive: true }); - fs.writeFileSync(path.join(userIdDir, 'index.tsx'), '// user index'); + fs.writeFileSync(path.join(userIdDir, '_index.tsx'), '// user index'); fs.writeFileSync(path.join(postsDir, '$postId.tsx'), '// post id'); const manifest = createRemixRouteManifest({ rootDir: tempDir }); - // users/$id/index.tsx should map to /users/:id (dynamic route) + // users/$id/_index.tsx should map to /users/:id (dynamic route) expect(manifest.dynamicRoutes).toContainEqual( expect.objectContaining({ path: '/users/:id', @@ -115,7 +115,7 @@ describe('createRemixRouteManifest', () => { const usersDir = path.join(routesDir, 'users'); fs.mkdirSync(usersDir, { recursive: true }); - fs.writeFileSync(path.join(routesDir, 'index.tsx'), '// root'); + fs.writeFileSync(path.join(routesDir, '_index.tsx'), '// root'); fs.writeFileSync(path.join(routesDir, 'about.tsx'), '// about'); fs.writeFileSync(path.join(usersDir, '$id.tsx'), '// user'); diff --git a/packages/remix/test/config/routeConversion.test.ts b/packages/remix/test/config/routeConversion.test.ts index e7f6fcadc6fe..53d2d53b668a 100644 --- a/packages/remix/test/config/routeConversion.test.ts +++ b/packages/remix/test/config/routeConversion.test.ts @@ -14,14 +14,6 @@ describe('Route Conversion Consistency', () => { expect(buildTime?.path).toBe('/about'); }); - it('should produce identical results for index routes', () => { - const buildTime = convertRemixRouteToPath('index.tsx'); - const runtime = convertRemixRouteIdToPath('routes/index'); - - expect(buildTime?.path).toBe(runtime); - expect(buildTime?.path).toBe('/'); - }); - it('should produce identical results for dynamic parameter routes', () => { const buildTime = convertRemixRouteToPath('users.$id.tsx'); const runtime = convertRemixRouteIdToPath('routes/users.$id'); @@ -62,9 +54,9 @@ describe('Route Conversion Consistency', () => { expect(buildTime?.path).toBe('/users/:id'); }); - it('should produce identical results for nested folder with index', () => { - const buildTime = convertRemixRouteToPath('users/index.tsx'); - const runtime = convertRemixRouteIdToPath('routes/users.index'); + it('should produce identical results for nested folder with _index', () => { + const buildTime = convertRemixRouteToPath('users/_index.tsx'); + const runtime = convertRemixRouteIdToPath('routes/users._index'); expect(buildTime?.path).toBe(runtime); expect(buildTime?.path).toBe('/users'); @@ -137,9 +129,9 @@ describe('Route Conversion Consistency', () => { expect(buildTime?.path).toBe(runtime); }); - it('should handle trailing index segments', () => { - const buildTime = convertRemixRouteToPath('users.profile.index.tsx'); - const runtime = convertRemixRouteIdToPath('routes/users.profile.index'); + it('should handle trailing _index segments', () => { + const buildTime = convertRemixRouteToPath('users.profile._index.tsx'); + const runtime = convertRemixRouteIdToPath('routes/users.profile._index'); expect(buildTime?.path).toBe(runtime); expect(buildTime?.path).toBe('/users/profile'); diff --git a/packages/remix/test/utils/utils.test.ts b/packages/remix/test/utils/utils.test.ts index cd8bb3f4f5e3..94bfdacc4d8b 100644 --- a/packages/remix/test/utils/utils.test.ts +++ b/packages/remix/test/utils/utils.test.ts @@ -99,10 +99,6 @@ describe('convertRemixRouteIdToPath', () => { expect(convertRemixRouteIdToPath('routes/_index')).toBe('/'); }); - it('should convert root index route', () => { - expect(convertRemixRouteIdToPath('routes/index')).toBe('/'); - }); - it('should convert static routes', () => { expect(convertRemixRouteIdToPath('routes/about')).toBe('/about'); expect(convertRemixRouteIdToPath('routes/contact')).toBe('/contact'); @@ -143,16 +139,6 @@ describe('convertRemixRouteIdToPath', () => { }); }); - describe('index route handling (non-underscore)', () => { - it('should handle nested index routes', () => { - expect(convertRemixRouteIdToPath('routes/users.index')).toBe('/users'); - }); - - it('should handle deeply nested index routes', () => { - expect(convertRemixRouteIdToPath('routes/admin.settings.index')).toBe('/admin/settings'); - }); - }); - describe('layout routes', () => { it('should skip pathless layout segments', () => { expect(convertRemixRouteIdToPath('routes/_auth.login')).toBe('/login');