ProNextJS / declarative-routing

NextJS Typesafe Routing System
MIT License
179 stars 13 forks source link

Automatic route detection for file-based routers #24

Closed kpervin closed 1 week ago

kpervin commented 1 week ago

Would it make any sense to potentially have automatic path detection? I created a script that may be useful on build:

async function getCurrentFileRoute(): Promise<string> {
  const path = await import("path");
  const { dir, name } = path.parse(__filename);
  /**
   * We split first then recombine so that we have bash/cmd/pwsh agnosticism
   */
  const separatedPath = dir.split(path.sep);
  const formattedDirPath = `/${separatedPath
    .slice(separatedPath.indexOf(".next") + 3) /* Path always resolves to ~/.next/server/(app|pages)/... */
    .join("/")}`;
  /**
   * If root of app/pages directory, return '/'
   */
  if (/^(pages|app)$/.test(formattedDirPath)) {
    return `/`;
  }
  /**
   * If we reach a file that is not indicative of a route,
   * return parent directory path as route
   */
  if (/(page|index|layout|routedef)/.test(name)) {
    return `${formattedDirPath}`;
  }
  /**
   * Return file route (mainly pages dir compatibility)
   */
  return `${formattedDirPath}/${name}`;
}

This way, if makeRoute is defined within the pages router, we can include it in the file that would also house getServerSideProps and etc, and in the app router it could be an independent file called routedef or included in page or layout.

This would mostly be for any frameworks that use file-based routing, and in this case it would be NextJS.

jherr commented 1 week ago

I'm happy to support the Pages router as well. I'm not sure how this fits into that though. Can you put together a PR?

kpervin commented 1 week ago

@jherr Maybe I'm misunderstanding where you're meant to be calling makeRoute. My thought would be to include it in the following ways:

pages/
├── index // makeRoute in here, resolves to `/`
├── _app
├── _document
├── about.js //makeRoute in here
├── blog/
│   ├── [slug].js // makeRoute in here
│   └── some_other_dir/
│       └── index // makeRoute here, resolves to `/blog/some_other_dir`
└── [someDynRoute]/
    ├── someStaticLeaf.js // makeRoute in here
    └── [anotherDynPath]/
        └── index // makeRoute in here, resolves to `/[someDynRoute]/[anotherDynPath]`
app/
├── page // makeRoute in here OR
├── routedef // put it in here (but not both)
└── dir/
    ├── page // makeRoute
    ├── layout
    └── child_dir/
        ├── page
        └── routedef // makeRoute
jherr commented 1 week ago

makeRoute is called in the index.ts file of @/routes to build a route component for a given route. In NextJS it imports a .info file located in each route directory to get the biographic information for the route (name, params, search params, etc.)

You use the components created by makeRoute and exported by @/routes as replacements for <Link> components.

makeRoute doesn't actually make a route, it makes a route link component.

kpervin commented 1 week ago

Hmmm, gotcha. Reason I'm thinking along these lines has to do with refactoring in case you need to move routes around, and therefore the new route would automatically be determined by the location in the directory tree. That being said, it's not going to be a frequent occurrence, but would save some peace of mind being able to have the route defined in the same location as the file serving the route. Additionally for get{Fn}Props in the pages router it can reuse the Zod schemas for queries and param typing respectively. I'm not familiar enough with the app router to say if that would be beneficial or not in that scenario.

However I think I may need to re-read the docs as your comment about the .info file makes me realize that potentially I don't fully understand how this library is used and am commenting based on half-comprehension.

jherr commented 1 week ago

That's actually the whole point of this. All you need to do is name the route and provide additional search parameter information and from then on you can use these declarative routes throughout your applications so that, should the routes move, or the parameters change, your code will change automatically based on the route changes, as well as break if you change the type contract.

Have you watched the video around this?

kpervin commented 1 week ago

@jherr I did but as said previously it's become apparent that I did not pay well enough attention 😅 My apologies for wasting your time with this.