solidjs / solid-router

A universal router for Solid inspired by Ember and React Router
MIT License
1.15k stars 147 forks source link

Advanced typings #110

Open MrFoxPro opened 2 years ago

MrFoxPro commented 2 years ago

I fell in love using https://github.com/mikeplus64/solid-typefu-router5 Now I'm missing this ability to see available routes and its params when using navigate from 'useNavigate', Link and so on. I think it's readlly worth to implement @mikeplus64 approach here. It gives you pleasure when writing code.

ryansolid commented 1 year ago

Now with stuff like the latest Tanstack Router being fully typed this sort of thing is picking up steam again.

I'd love to work with people on how to accomplish this within the framing of the router. Keep in mind a lot of the router is designed a specific way for performance and meta-framework integration consideration. But I'd love to do better here if people could help me.

mikeplus64 commented 1 year ago

I'm now working on a successor to solid-typefu-router5 that:

  1. Has its own router backends. To be honest I used router5 only because I figured it must be abstracting over some really hairy web/node APIs that I had no desire at all to learn, but it turns out the history API is really small. Unfortunately router5 seems unmaintained nowadays and has a few bugs.

  2. Has a simpler syntax for specifying router definitions, and more type-safety for parameter types. The idea is to support things like:

const router = createRouter({
  blog: {
    "?page: natural": 0, // "/blog?page=123"  query param
    ".id: natural": 0, // "/blog/543" paramaterised URI component
  },
  cups: {
    "?page: natural": 0, // "cups?page=xxx"
    "cup/.cupId:uuid": { // "cups/cup/xxxx-xxx-xxx-xx"
      "stage/.stageId:uuid": {} // "cups/cup/.../stage/...
    }
  }
}, { // types to support in parameters
  /* natural: { decode(input: string): number | undefined, encode(value: number): string } */
  natural: { decode: ...parseInt blah blah blah..., encode: String }
  uuid: { ... }
});

The unique IDs roughly correspond to the URIs, and are, for each route (that you'd use in a type-safe Link or navigate): /blog, /blog?page, /blog/.id, /cups, /cups?page, /cups/cup/.cupId, /cups/cup/.cupId/stage/.stageId.

In case of ambiguity in the routes, it would attempt to parse routes doing using literal path components, then path component parameters, then query parameters. If you had ambiguity because of parameters using different types, behaviour is undefined; support this by making a new type that combines the ones you need to support.

  1. Has a data layer/context that reloads data according to suffix of the diff of the URI change.

So if you navigate from "/blog/42" to "/blog/43" you do not reload any data you loaded for "/blog", but you do for "/blog/.id".

For sites where basically everything rendered by SolidJS is determinable from the URI (with a lot of REST/GraphQL/whatever in between), I think this would be quite convenient and make it so you don't need to necessarily create large context objects for any shared data.

I think this would work by an API like router.addData<ID extends RouteID<typeof router>, T>(id: ID, data: () => Promise<T>): magicNewRouterType, and adding making data T available when matching on a route using a Router (like https://github.com/mikeplus64/solid-typefu-router5/blob/6ed7ef9f83030ed4a7ab597a91d7fabcb88eb1b9/example/src/index.tsx#L162) or ShowRoute etc, similar to how params are available in solid-typefu-router5.

I would probably keep it as minimalist as possible, leaving caching questions up to the programmer. It probably would use reactive data that gets reconcile'd when updated though.

Repo is https://github.com/mikeplus64/solid-cartography which also seems like a much better name than solid-typefu-router5 :).

marbemac commented 1 year ago

@mikeplus64 off the top of your head, do you see any reasons why the approach you took with router5 would not work with solid-router?