kit
kit copied to clipboard
Reusign nested subroutes
Describe the problem
Currently, there is no easy way to reuse a set of subroutes across other routes.
Simple example
For example, let's say that you have a 3-step modal for creating something. You may want to access the modal from
/landing/modal
/landing/modal/step1
/landing/modal/step2
/settings/user/modal/
/settings/user/modal/step1
/settings/user/modal/step2
There is no clean way to reuse the /modal/*
routes.
Real case
I have a website about sports, and I have the following routes:
/dailies --> 2 column layout
/live/feed --> 2 rows layout
/strategy/[stratId] --> 2 columns layout
/filters --> 1 row + 1 row with 2 columns layout
In all those cases, the left (top) column (row) will show a predefined list of matches in different configurations and appearances. Clicking the match will display the match data in the left (bottom) row (column). The match data displayed is the same no matter where you access it. The navigation for the matches looks like this:
/match/{matchId}
/match/{matchId}/tab1
/match/{matchId}/tab1/subtab1-1
/match/{matchId}/tab1/subtab1-2
/match/{matchId}/tab2/subtab2-1
/match/{matchId}/tab2/subtab2-1
/match/{matchId}/tab3
What I want is to have all of the following routes:
/dailies
/dailies/unique-daily-stuff-cant-be-used-with-matches
/dailies/match/{matchId}
/dailies/match/{matchId}/tab1
/dailies/match/{matchId}/tab1/subtab1-1
/dailies/match/{matchId}/tab1/subtab1-2
/dailies/match/{matchId}/tab2/subtab2-1
/dailies/match/{matchId}/tab2/subtab2-1
/dailies/match/{matchId}/tab3
/live/feed
/live/feed/unique-feed-stuff-cant-be-used-with-matches
/live/feed/match/{matchId}
/live/feed/match/{matchId}/tab1
/live/feed/match/{matchId}/tab1/subtab1-1
/live/feed/match/{matchId}/tab1/subtab1-2
/live/feed/{matchId}/tab2/subtab2-1
/live/feed/{matchId}/tab2/subtab2-1
/live/feed/{matchId}/tab3
(...)
/filters/match/{matchId}/tab3
As you can see, the matches subroutes are repeated across all higher-level routes, and the page I want to render is the same; their position will change.
Describe the proposed solution
- Add a new syntax to the routing system
&(group-name)
- Let's name the token a Shared Group
- A folder named
&(group-name)
at the routes root indicates a group of routes that can be shared - A shared folder is not generated by itself nor does it create routes by itself
- Adding a file named
&group-name.ts
in a folder will automatically "insert" all the routes from the shared group into that folder - any potential configuration would be added to the above mentioned .ts file
Example:
routes/
├── dailies/
│ ├── something/
│ │ └── +page.svelte
│ ├── otherthing/
│ │ └── +page.svelte
│ └── match/
│ └── &matchGroup.ts
├── live/
│ ├── feed/
│ │ ├── match/
│ │ │ └── &matchGroup.ts
│ │ ├── subfeed/
│ │ │ └── +page.ts
│ │ └── +layout.svelte
│ └── not-feed/
│ └── +page.svelte
└── &(matchGroup)/
├── [matchId]/
│ └── +page.svelte
└── +layout.svelte
Would generate something similar to:
routes/
├── dailies/
│ ├── something/
│ │ └── +page.svelte
│ ├── otherthing/
│ │ └── +page.svelte
│ └── match/
│ ├── [matchId]/
│ │ └── +page.svelte
│ └── +layout.svelte
└── live/
├── feed/
│ ├── match/
│ │ ├── [matchId]/
│ │ │ └── +page.svelte
│ │ └── +layout.svelte
│ ├── subfeed/
│ │ └── +page.ts
│ └── +layout.svelte
└── not-feed/
└── +page.svelte
Alternatives considered
Option 1 - do nothing and let the user replicate the routes.
- Let the users manually create the nested replicated folder structure
- Keeps the parity between folder structure and routes
- Users can use components to have a single code shared between all routes as exemplified on the docs
- Creating new subroutes that need to be shared will, however, require users to create the new routing folder in all higher level router.
- On the real example above: Adding a tab4 requires creating 4 new folders and 4 new individual
+page.ts
files that will be exactly the same. Forgetting to create one of these folders will result in a broken navigation.
- On the real example above: Adding a tab4 requires creating 4 new folders and 4 new individual
Option 2 - Do nothing and encourage users to use route parameters and svelte:components
- Structures like
/[category]/match/(...)
would allow for a single route that reuses the subroute - Combined with param matching and an svelte:components the [category] both +page and +layout can be dynamically selected to change between upper route options
- This falls apart when categories have other subroutes that differ between them
- To add a new route, you need to update at least three files, the matcher, the +page, and the +layout from the upper route (if they exist)
- It is annoying to have that many switch statements for alternating the [category]
- The folder structure gets less intuitive
Option 3 - Move away from file-based routing
- Moves away from one of the project's core decisions
- Time consuming
- Breaking change
- One of the breakiest changes that could happen ?
Option 4 - Different syntax or structure for reusing routes
- Please do iterate on the proposed syntax, I have not dedicated the amount of effort needed for something this complex
- This current syntax tries to reuse concepts that already exist on sveltekit
- The current syntax borrows from the group syntax
(group)
and expands it to a "shared" group - It also borrows from the breaking out of layouts syntax
[email protected]
- The current syntax borrows from the group syntax
Importance
would make my life easier
Additional Information
Angular (that does not use file-based routing) had a pretty good solution: create a new module with the subroutes and import it as the child of any other existing route. It looks something like:
[
{
path: "dailies",
component: DailiesComponent,
children: [
{ path: "unique-daily-stuff", component: UnrelatedComponent },
{
path: "match",
loadChildren: () => import("./match.module").then((m) => m.MatchModule),
},
],
},
{
path: "live",
component: LiveComponent,
children: [
{
path: "feed",
children: [
{
path: "match",
loadChildren: () =>
import("./match.module").then((m) => m.MatchModule),
},
{
path: "unique-daily-stuff",
component: UnrelatedComponent,
},
],
},
],
},
];
Despite not being file-base it exemplifies what would be the goal of this proposal.
Regarding option 2: You can also use [...rest]
routes along with a matcher to determine which of the routes apply
dummdidumm
Yes, tnat is indeed true.
Beyond having the previously mentioned down sides using [...rest]
would also prevent me from using optional parameters in any of the subroutes in Option 2.
Which is really not ideal as they should be completely independent. They just happen to share some similar parts.