kit
kit copied to clipboard
`route.segment` as a way to get the specific path to the current `+layout.*.js` file
Describe the problem
Sometimes it would be useful to know "why" a certain load
function within a +layout.*.js
file gets executed.
A specific use-case is: breadcrumb navigation, where each +layout.*.js
file can contribute its own metadata (url, title, etc.) to an array. In this case each layout would need to know it's specific part of the url. Currently this requires manual parsing of the url.pathname
. in each file
Describe the proposed solution
It would be great to have a way to get the information for which part of the url a specific layout file was called.
I think a new segment
(or better name) property inside the route
object for all load
functions would make sense.
e.g. with this folder structure
/products
/[id]
/edit
/+layout.server.js
/+page.js
/+layout.js
/+layout.server.js
when accessing the url /products/123/edit
following route.segment
schould be defined in those files:
-
/products/+layout.server.js
:/products
-
/products/[id]/+layout.js
:/products/123
-
/products/[id]/edit/+layout.server.js
:/products/123/edit
For all +page.*.js
the segment
would be equal to url.pathname
.
Alternatives considered
Leave it as it is.
Importance
would make my life easier
Additional Information
No response
I've been looking for this very thing, I'll paraphrase the discord thread:
Can each +layout.js access their own route id?
I want to use it for some breadcrumb logic.
ie: assuming I am accessing the URL /users/david/edit
I would do:
/users/+layout.js
$breadcrumbs.add(theRouteIdForThisLayout, 'Users')
ie:
$breadcrumbs.add('/users', 'Users')
/users/[username]/+layout.js
$breadcrumbs.add(theRouteIdForThisLayout, 'Users')
ie:
$breadcrumbs.add('/users/[username]', 'David King')
/users/[username]/edit/+layout.js
$breadcrumbs.add(theRouteIdForThisLayout, 'Users')
ie:
$breadcrumbs.add('/users/[username]/edit, '✏️ Edit')
This ^ logic would populate my breadcrumb data:
[
{ path: `/users`, title: 'Users' },
{ path: `/users/david`, title: 'David King' },
{ path: `/users/david/edit`, title: '✏️ Edit' },
]
It feels similar to $types in that it's context aware / specific to the file.
Although, for this specific case, I'd not be interested in the route.id, but rather the resolved part of the route, in order to be used in a link <a href={segment}>...
- /users/[username] - not useful here
- /users/david - better
A layout has no id, only pages have it. Something breadcrumb-y built in would help you with that better probably, something like "the current page has the following upper pages in its tree" - although that's probably not a solution for some cases since the folder tree and the perceived route hierarchy wouldn't necessarily correlate.
@dummdidumm that would be ideal. Having access to "parents" could be a great solution. Not sure how typing would work though.
Thinking out loud, a Breadcrumbs component may look like:
<script>
import parents from '$app/stores';
</script>
{#each parents as parent}
<a href={parent.url.pathname}>
{parent.data.title}
</a>
{/each}
As you can see, the title
param is problematic as each parent can have different data structures.
A layout has no id, only pages have it.
I thought routes had ids? And they're made up of pages and layouts...
The route.id
to the current layout/load function would be pretty nice. However I don´t think it´s very obvious how to implement this. Statically replacing a string like CURRENT_ROUTE_ID
in files within routes could be possible...
With that route id it should be possible to extract the actual path slice using sveltekits router.
This feels like something that could be done in userland, no?
const _depth = 3;
export function load({ parent, url }) {
const { breadcrumbs } = await parent();
const breadcrumb = url.pathname.split('/').slice(0, _depth).join('/');
return {
breadcrumbs: [...breadcrumbs, breadcrumb]
};
}
The one bit that's missing is knowing the depth without having to hard-code it. How important would that be? (I prefer depth to segments
since it feels more general — could be used with route.id
as well as url.pathname
, etc.)
This feels like something that could be done in userland, no?
Almost everything can be done in userland ^^.
But like you ready mentioned, you need to hardcode the depth
and that is not ideal for refactoring reasons. And you will end up with a line of code that get's repeated in every singe load function, where you need to manually parse the segment.
So if SvelteKit
would provide that functionality, it would eliminate 2 lines of code (which have some potential to mess them up) per load function.
-const _depth = 3;
-export function load({ parent, url }) {
+export function load({ parent, route }) {
const { breadcrumbs } = await parent();
- const breadcrumb = url.pathname.split('/').slice(0, _depth).join('/');
return {
- breadcrumbs: [...breadcrumbs, breadcrumb]
+ breadcrumbs: [...breadcrumbs, route.segment]
};
}
I just experimented a bit and additional to segment
I would also wish that SvelteKit
would provide a depth
property on the route
object. With the depth
property it would be possible to keep the parallel data loading feature (no await parent()
) intact and still be able to implement a breadcrumb array with the correct order.
https://stackblitz.com/edit/sveltejs-kit-template-default-gbdmhv?file=src/routes/a/+layout.server.ts
open the appplication and navigate to
/a
,/a/b
or/a/b/c
Already totally possible in userland, but requires additional effort to maintain and could cause some issues when refactoring or copy and pasting code from another route.
It doesn't feel like it belongs on route
, to be honest — the route doesn't change between load
functions. There is some precedent for event
changing between load
functions, because of the data
property, so if it belongs anywhere it's there.
On reflection, 'depth' is a rather ambiguous concept though — what is its value inside src/routes/foo/[...bar]/+layout.js
when you visit /foo/x/y/z
?
- is it 0, because there are no parent layouts?
- is it 2, because there are two directories between it and
src/routes
? (Useful for manipulatingroute.id
) - is it 4, because the path has four segments? (Useful for manipulating
url.pathname
)
If it's based on path segments, in +page.js
is the depth affected by the value of trailingSlash
?
I'm asking these questions less to figure out the correct answer, more to point out that it's inherently confusing to have such a thing in the framework.
The concept hitherto referred to as 'segment' is less confusing, though 'segment' is a bad name (that usually refers to a part of a pathname that doesn't include a /
character). Not sure what a better one would be.
It doesn't feel like it belongs on
route
, to be honest — the route doesn't change betweenload
functions.
Right, this would not rerun unless someone uses await parent()
. Similar to #6315 something is needed that rereuns each time a +page load
get's executed.
I'm asking these questions less to figure out the correct answer, more to point out that it's inherently confusing to have such a thing in the framework.
I see. Thanks for your detailed response. The depth
concept certainly does not belong into the framework.