copy/past generate-remix-routes.ts
next to remix.config
and generate routes with npx tsx generate-remix-routes.ts
Last active
October 13, 2023 22:57
-
-
Save heiso/322050c72dde922293bb565c61d6c8d7 to your computer and use it in GitHub Desktop.
Generate remix routes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { readConfig } from '@remix-run/dev/dist/config.js' | |
import type { ConfigRoute, RouteManifest } from '@remix-run/dev/dist/config/routes.js' | |
import { writeFileSync } from 'fs' | |
import { format, resolveConfig } from 'prettier' | |
const outputPath = `routes.ts` | |
function buildPath(routes: RouteManifest, route: ConfigRoute): string { | |
const result = [] | |
if (route.parentId) { | |
result.push(buildPath(routes, routes[route.parentId])) | |
} | |
if (route.path) { | |
result.push(route.path) | |
} | |
return result.join('/') | |
} | |
function buildParams(path: string, input: boolean = false) { | |
return path | |
.replace(/'/g, '') | |
.split('/') | |
.filter((part) => part.startsWith(':')) | |
.map((part) => part.replace(':', '')) | |
.map( | |
(param) => | |
`${param}: string${input ? ' | number' : ''}${param.endsWith('?') ? ' | undefined' : ''}`, | |
) | |
.join(',') | |
} | |
;(async () => { | |
const { routes } = await readConfig() | |
const paths = [ | |
...new Set( | |
Object.keys(routes).map((key) => { | |
let path = buildPath(routes, routes[key]) | |
if (path === '') { | |
path = '/' | |
} | |
return `'${path}'` | |
}), | |
), | |
] | |
const content = ` | |
export const routerPaths = {${paths | |
.map((path) => { | |
if (!path.includes('/:')) { | |
return `${path}: ${path}` | |
} | |
return `${path}(params: {${buildParams(path, true)}}) { | |
return buildPath(${path}, params) | |
}` | |
}) | |
.join(',')}} as const | |
export const unsafeRouterPaths = {${paths | |
.map((path) => { | |
return `${path}(params: Record<string, unknown>) { | |
return unsafeBuildPath(${path}, params) | |
}` | |
}) | |
.join(',')}} as const | |
export type RouterPath = keyof typeof routerPaths | |
export type RouterParams = {${paths.map((path) => `${path}: {${buildParams(path)}}`).join(',')}} | |
type InputParams = {${paths.map((path) => `${path}: {${buildParams(path, true)}}`).join(',')}} | |
// eslint-disable-next-line @typescript-eslint/no-unused-vars | |
function buildPath<TRouterPath extends RouterPath>(route: TRouterPath, params: InputParams[TRouterPath]) { | |
return route | |
.replace(/'/g, '') | |
.split('/') | |
.map((part) => | |
part.startsWith(':') ? params[part.replace(':', '').replace('?', '') as keyof InputParams[TRouterPath]] : part, | |
) | |
.filter((part) => part !== undefined) | |
.join('/') | |
} | |
function unsafeBuildPath<TRouterPath extends RouterPath>( | |
route: TRouterPath, | |
params: Record<string, unknown>, | |
) { | |
return route | |
.replace(/'/g, '') | |
.split('/') | |
.map((part) => (part.startsWith(':') ? params[part.replace(':', '').replace('?', '')] : part)) | |
.filter((part) => part !== undefined) | |
.join('/') | |
} | |
` | |
try { | |
const formatted = await format(content, { | |
...(await resolveConfig(process.cwd())), | |
parser: 'typescript', | |
}) | |
writeFileSync(outputPath, formatted) | |
} catch (err) { | |
console.log(content) | |
} | |
})() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { redirect, type LoaderArgs } from '@remix-run/node' | |
import { routerPaths, type RouterParams, type RouterPath } from '../routes' | |
const THIS_PATH = '/my/:awesome?/route' satisfies RouterPath | |
export async function loader(args: LoaderArgs) { | |
// Can type params | |
const params = args.params as RouterParams[typeof THIS_PATH] | |
// params.awesome?: string | undefined | null | |
const count = Number(params.awesome) || 0 | |
// Can build path with params | |
return redirect(routerPaths[THIS_PATH]({ awesome: count + 1 })) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment