Simpler custom layouts #6124
Replies: 27 comments 100 replies
-
I like the grouping mechanism because loading and or layout ui often go hand in hand with feature areas. I don't like that it potentially creates more folder depth, but I can live with that - but curious to hear other people's opinions. An alternative would be to keep the current system but without the possibility to inherit from siblings - you would always go up the tree, and all named layouts inherit from the default layout automatically. This should achieve the same without the grouping mechanism. One question about segments: if I want to rewind to the layout within One edge case I'm not sure how it's handled: what if there are multiple segments in the tree with the same name. What to do if you want to jump past the first one? One note about |
Beta Was this translation helpful? Give feedback.
-
This is slightly off topic (slightly sorry), but slightly related: This proposal creates a solution that uses slots to put a modal page in a simple page. |
Beta Was this translation helpful? Give feedback.
-
I can't picture how this would be usable, wouldn't pages only belong to one "group" or another? What if they need to take part in two groups at the same time? i.e. one for auth, one for some other context I'm picturing a site like firebase console, where you have auth and you might have a selected project. Currently, I'd use a layout for loading the selected project data that becomes the context, and that layout uses another that ensures auth ... but other things also need to use the auth layout as well (e.g. user preferences, billing, profile) without any project context. I don't see how I could have an (auth) group and a (project) group and pages use both. |
Beta Was this translation helpful? Give feedback.
-
I understand the rationale for this proposal but I think the solution is digging the hole even deeper. The problem stated was that named layouts were confusing. The solution proposes a new abstraction that adds more "api" to file and directory names, which IMO will increase the confusion and learning curve. Using a hierarchy to determine routing is reasonable because it maps 1:1 with a URL structure, which is indeed a hierarchical tree structure with no loops - read: "not a graph". But as soon as we want to break out of the layout determined by the hierarchy that determines routes, we are attempting to create a graph. (Please let me know if that's not clear and I'll provide more details.) I liked how RH (or someone... can't remember) described the render tree as different than the data tree. In reality, we have at least 2 trees and 1 undirected graph. Trees: route, data. Graph: render, (where layout is part of render.) I recommend only using directories and filenames for the "api" of the route concern. Which means URLs are determined by directories and filenames. Ideally rendering is determined by code in the templates, (which would mean we have to solve the static determinism problem RH mentioned in the discussion HEAD.) And data... well, that's more difficult but using +X.server.js seems ... fine ... for now? Tl;DR - I'd suggest moving away from treating the file and directory names as an API and move toward separating routing vs render "APIs". p.s. One of the great things (and strongly intended design decisions) of SvelteKit is the drive toward type safety. Thanks as always for reading |
Beta Was this translation helpful? Give feedback.
-
I also think the existing design could be easier because it really complicates the file naming. Especially if you are just starting out it could be quite difficult to understand how layouts work. What I don't like about this approach
Here's my suggestion: Why not having a separate folder
The layouts could be applied by this:
<Layout name="admin">
<h1>Admin Dashboard</h1>
<div>....</div>
</Layout> Nested layouts could be done by this:
<Layout name="admin">
<h1>Admin Dashboard</h1>
<Layout name="product">
<div>...</div>
</Layout>
</Layout> Advantages of this approach
I'm still a beginner, so I can't really tell if that would be a good approach or not. But from the perspective of a beginner, this looks very easy and logical. |
Beta Was this translation helpful? Give feedback.
-
I'm sure you'll all hate this, but expressed in a special comment block at the top would solve everything ... <!-- use-layout=whatever -->
<script>
...
</script> |
Beta Was this translation helpful? Give feedback.
-
Another option might be something like this:
Specify all the layouts in a Not sure how you would go about adding a layout to the absolute top-level though. Maybe a Unsure how you would "eject" from layouts. Maybe something like |
Beta Was this translation helpful? Give feedback.
-
My hesitation with the groups is that it really messes with my head on the routing. Especially if those (directories) are collapsed. Quick side note: how in the world do y'all create those fancy-looking folder/file structures?? We've already gone to a directory centric approach to defining routes. What if we did the same for layouts?
This keeps the layout structure separated from the route structure, while (I think?) simplifying things. What I don't like about my idea:
|
Beta Was this translation helpful? Give feedback.
-
I don't think grouping is a good idea as it would as well make perfect sense to just split the two groups into 2 parent routes given how different they are (and redirect if they accessing the parent route) src/routes/
+ ├ app/
│ ├ dashboard/+page.svelte
│ ├ item/
│ │ ├ [id]/+page.svelte
| │ │ └ edit/+page.svelte
│ │ └ +layout.svelte
│ └ +layout.svelte
+ ├ marketing/
│ ├ about/+page.svelte
│ ├ testimonials/+page.svelte
│ └ +layout.svelte
├ admin/+page.svelte
└ +layout.svelte still there would be a problem where app and marketing pages would use the root layout. For this I suggest we can write a single @ which indicates it does not inherit any layout, such that the child pages of that route would also do the same: src/routes/
+ ├ app@/
│ ├ dashboard/+page.svelte
│ ├ item/
│ │ ├ [id]/+page.svelte
| │ │ └ edit/+page.svelte
│ │ └ +layout.svelte
│ └ +layout.svelte
+ ├ marketing@/
│ ├ about/+page.svelte
│ ├ testimonials/+page.svelte
│ └ +layout.svelte
├ admin/+page.svelte
└ +layout.svelte Then for child pages that would like to escape we can write like, which fall backs to src/routes/
├ app@/
│ ├ dashboard/+page.svelte
│ ├ item/
│ │ ├ [id]/+page.svelte
+ │ │ └ edit/[email protected]
│ │ └ +layout.svelte
│ └ +layout.svelte
├ marketing@/
│ ├ about/+page.svelte
│ ├ testimonials/+page.svelte
│ └ +layout.svelte
├ admin/+page.svelte
└ +layout.svelte such that if we want to fallback to src/routes/
├ app@/
│ ├ dashboard/+page.svelte
│ ├ item/
│ │ ├ [id]/+page.svelte
+ | │ │ └ edit/[email protected]
│ │ └ +layout.svelte
│ └ +layout.svelte
├ marketing@/
│ ├ about/+page.svelte
│ ├ testimonials/+page.svelte
│ └ +layout.svelte
├ admin/+page.svelte
└ +layout.svelte for me this way seems to be more straight-forward and still maintain the route hierarchy. |
Beta Was this translation helpful? Give feedback.
-
TL;DR
I like the part of the proposal where a page can reference the root layout using Group problem 1. It could potentially make some refactors difficultIf a team decides to change a group name then that could block some other teammates' changes upstream and would require careful planning. Bigger teams may have potentially bigger conflicts. Group problem 2. What if we need more groups?Original example for reference
An app may require more groups in order to have new "root layouts"; such as item reviews, store locator, user profiles, or (marketing) sponsorships; and the new app routes require a different root layout because they don't utilize a common navigator or footer because they're meant to be embeddable (iframe) app pages. Altogether, that would look something like this: src/routes/
├── (app)/
│ ├── dashboard/+page.svelte
│ ├── item/
│ │ ├── [id]/
│ │ │ ├── edit/[email protected]
│ │ │ └── +page.svelte
│ │ └── +layout.svelte
│ └── +layout.svelte
+── (app-embeddable)/
+ ├── item/[id]/reviews/+page.svelte
+ ├── stores/
+ │ ├── [id]/+page.svelte
+ │ ├── +page.svelte
+ │ └── +layout.svelte
+ ├── users/
+ │ ├── [id]/+page.svelte
+ │ └── +page.svelte
+ └── +layout.svelte
├── (marketing)/
│ ├── about/+page.svelte
│ ├── testimonials/+page.svelte
│ └── +layout.svelte
+── (marketing-sponsors)/
+ └── sponsors/
+ ├── +page.svelte
+ └── +layout.svelte
├── admin/+page.svelte
└── +layout.svelte And what if a page needs to render both as an app and as an embeddable page? We could add a I hope this example doesn't come across as contrived since I had worked on such an app with embeddable requirements. A fair argument would be having the Potential solution: root layoutsI propose keeping named layouts and introducing a "layout root assignment" by appending Given the following: src/routes/
-── (app)/
├── admin/+page.svelte
│── dashboard/+page.svelte
+── embed/
+ ├── item/[id]/reviews/+page.svelte
+ ├── stores/
+ │ ├── [id]/[email protected]
+ │ ├── +page.svelte
+ │ └── +layout.svelte
+ ├── users/
+ │ ├── [id]/+page.svelte
+ │ └── +page.svelte
+ └── [email protected]
│── item/
│ ├── [id]/
│ │ ├── reviews/
│ │ │ ├── +page.svelte
│ │ │ └── [email protected]
│ │ ├── edit/[email protected]
│ │ └── +page.svelte
│ └── +layout.svelte
│ └── +layout.svelte
-── (marketing)/
+── about/+page+marketing.svelte
+── sponsors/
+ ├── +page.svelte
+ └── [email protected]
+── testimonials/[email protected]
├── +layout.svelte
+── +layout-marketing.svelte The behaviour would be:
I understand the big question is "is this intuitive?" and not "is this clean?". At a glance, it's not intuitive how Revisiting layout functionalityCompared to the imperative approach in Astro, Nuxt, and Jekyll, I think we would lose functionality if we don't have the flexibility of named layouts. With the groups proposal, we wouldn't have selective layout inheritance (i.e. From my understanding, layouts require the following functionality:
Static site generators like Jekyll require every page to explicitly define their layout in the page's code. A layout can also slot into other layouts, but it's inflexible: once a layout consumes another layout, that's defined permanently. Breaking out of that requires duplicate layouts. SvelteKit today solves problems 1 and 2 and adds bonus functionality thanks to the file-based router:
That's great, athough some applications may run into inflexibility concerns when a page should not consume a certain sibling or parent layout, and for that I can see how this discussion can yield several potential solutions. I hope my proposal introduces enough flexibility without introducing too much new complexity, compared with groups. Thanks for your effort. |
Beta Was this translation helpful? Give feedback.
-
What I like about this proposal is that it keeps layouts under In the current structure, layout gets referenced through In the proposed structure, the fact that I can scan my directory structure and make sense of These is more like a trade-off between |
Beta Was this translation helpful? Give feedback.
-
Even if Introducing The proposal to create an |
Beta Was this translation helpful? Give feedback.
-
I'm not against the proposal. But here goes another idea... Instead of letting layout inherits layout, can we switch to something like directory uses layout or segment uses layout? The default example becomes:
So there are three choices:
and you can use multiple of them ( The layout is scoped within a segment. This means two things:
Compared to the default proposal:
One more thing I forgot to mention is where do you put the layout files if there are multiple directories for the segment? For example, what happens if I put the
For the original example, I should've put the
But yes, the tree grows and you can't decide this ahead of time. Use whatever directory you deem appropriate. EDIT: well, what about
|
Beta Was this translation helpful? Give feedback.
-
It looks like you are trying to use one concept to solve two separate problems. Let directories specify routes, period. Now find another means of associating layouts. To my way of thinking the problem is really how to bi-directionally link components and layouts. Layouts already link to components with a slot. So now use a compatible means of linking components to layouts. In these terms, layouts are really just components by another name. The real thing that distinguishes a layout is that it is not a route, it is implicitly used by routes. That suggests layouts don't belong under /routes at all. You mentioned a possible, but rejected, solution in JavaScript. I'd think about an HTML solution that is the counterpart to |
Beta Was this translation helpful? Give feedback.
-
Can anyone explain in more detail why |
Beta Was this translation helpful? Give feedback.
-
With a folder based routing, (imho), having a For example this:
would be this:
If (imho) this is
What do people think about this? |
Beta Was this translation helpful? Give feedback.
-
@theetrain makes a good point. Is there really a requirement for inheritance from layout to layout? I know in my app there isn't and I can't think of a use case where there would be. How many people really want multiple nested layouts? If it is for rare esoteric use cases then consider having the simple, easy to understand layout design that @theetrain describes, and make the few people who want more employ the JavaScript imports that @Rich-Harris described. |
Beta Was this translation helpful? Give feedback.
-
Throwing an idea on the wall that I haven't fully baked, so bare with me. JSON route configuration fileTo address the needs for complex route inheritance, "breaking out" of route inheritance and the fact that
{
"layout": "@post",
"prerender": true
} Which could map to Handle any route configurationAny route specific configuration could live here (layout, prerender, hydrate, router, etc). {
"layout": "foo@bar",
"prerender": true,
"hydrate": false,
"router": false
} Static analysisSince it's JSON, it's statically analizable. Resolves point 1. Works for layout inheritance/error pages tooCould be applied to a layout or error via the same mechanism perhaps ( This could help allow for "grouped layouts" by allowing you to indicate one layout is nested within another. For example, in {
"layout": "@admin"
} Inherit any layout anywhereYou could reference a layout by path: {
"layout": "foo/bar/baz"
} Would map to This means you could map to any arbitrary layout in your app irrespective of its hierarchy and would negate the need for all the fancy file name gymnastics. Kit could notice if that path was invalid and throw an error. Partially resolves point 2. Resetting layout to defaultSetting layout to "@" defaults to the root layout (or maybe {
"layout": "@"
} Partially resolves point 2. Custom named layoutsFor custom named layouts (eg "marketing", could do: {
"layout": "@marketing"
} Which could map to {
"layout": "foo/bar/baz@biz"
} Would map to Simple default caseFor the default case of a route just using the default layout, no config option needs to be set, only set it when you want to override the default hierarchical inheritance. JSON is standard and simpleAnd finally, we're all used to JSON for configuration, so I don't think it would be too confusing. FINThanks for coming to my TED talk ✌️ |
Beta Was this translation helpful? Give feedback.
-
Another possibly divisive suggestion: Can we get rid of layouts? Do we even need them? ... Hear me out... Why not do what other routing libs do and just allow for a Now that we have per route "middleware" or whatever we want to call it, we can build the data server-side and push down through And if you needed a child URL to break out of the parent component, you would put that logic into the parent component itself while having the data returned from the server stuff something into This is how it works with VueRouter and it's pretty nice. |
Beta Was this translation helpful? Give feedback.
-
I personally don’t find a better way for the group job.
Honestly, to introduce this third level of abstraction, we need something to materialize it, I’m fine with you proposal. I’m curious to see what you’ll imagine for the next one. |
Beta Was this translation helpful? Give feedback.
-
While I might be late to the party (hopefully more than 3 days of discussion is being given to important changes like these though), I find that the current system of named layouts is, in a word, gross, and this new proposed system does little to improve. I think this is where the filename magic in kit started to get out of hand, and moving away from using filenames as an API is better for readability, tooling, and offers more flexibility in the future. Current and older systemsGoing back to a time before named layouts, you were restricted to two options:
This system was quite simple, and for many apps was perfectly sufficient. The issues came with keeping code DRY, since layout resets required you to put all of your layout code in one file, unable to take advantage of the fact that you've already written that code before. Resets were also an all-or-nothing solution which lacked control and could end up being very clunky with larger, more intricate apps. With the introduction of named layouts, all of this was flipped on its head, since they offered so much control over how your layouts were inherited. With so much flexibility, however, came a loss of simplicity. Many experienced devs, as well as myself, are left head scratching trying to remember what the rules are for where layouts can inherit from, and "where the heck is this layout defined," and shoving layout inheritance into filenames made it frustratingly opaque to debug. I wouldn't call it a nightmarishly complicated task, but constantly running into issues like that could definitely put a damper on one's workflow. Design considerationsThe fundamental question when designing systems like these is where to place the balance between simplicity, consistency, and flexibility. Layout resets excelled in the first, named layouts excelled in the last, and I think that a new system should strike a balance between these. An important realization is that (applying the classic 80/20 rule) ~80% of your code is going to use only ~20% of the available features. It's going to be much more common in most, if not all apps, that pages will not need to break out of the classic layout nesting system. Knowing this, a new system should preserve the trait that the majority of cases will be the simplest to deal with. The point in contention is how to handle the abnormal, more complex, and special cases in need of fine control, while also striking that balance between simplicity and flexibility. I think many people here make a good point by acknowledging that layouts run double-duty in a kit app, being integral to both the render tree and the load tree. These two systems are often, but not always, correlated, so I don't see a need to completely separate them. The current My proposalWith a lot of fluff out of the way (mostly to get my own brain warmed up), here's how I think layouts should be designed and used. For the simple cases where layouts are neatly nested inside one another and load functions are called in nice succession (assuming
Now for the real meat of the proposal: how to break this system. If you stop to think about it, layouts are really just components with a slot and some extra magic behind the scenes. Why not take inspiration from the way we use components? This has the advantage of being easy to understand for those who have learned svelte before kit, and provides a consistent syntax. I propose that in order to break out of the classic layout nesting, one would import a layout just as they would import a regular component, and then use it like they would use a regular component. Since there are already methods available to generate an import tree without actually running the code, this seems like it falls within the constraints of "statically analyzable". Here's an example, where <script>
import FeaturedLayout from 'src/routes/blog/+layout-featured.svelte'
</script>
<FeaturedLayout>
<h1>Here is where your specific code for this layout</h1>
<slot></slot>
</FeaturedLayout> Note that the named layout syntax is used, but only to disambiguate this from any other layouts you happen to have made. The contents of the layout filename are completely arbitrary and don't affect how it's used, as long as it starts with The classic layout nesting could also pick up from wherever the layout is imported from, in this case checking for layouts in In order to keep the import tree from being a complete free-for-all, there should be restrictions about where layouts can be imported from. One potential idea: layouts can only be imported from directories that are direct parents of the current directory, which includes the Note that having an actual import statement in the file makes many things much easier. First, it completely removes the ambiguity of "where is this layout coming from". Second, and more importantly, it makes it much easier to use existing tooling to its full extent. While I can't speak specifically to the design of kit tooling, I predict that analyzing filenames to look for the layout name, then digging through the filetree to find the layout is a hassle. How the heck should you display something like a "this layout does not exist" error anyways if the error is in the filename? This is probably why (afaik) there is exactly zero tooling out there that understands these kinds of "imports" inside the filename. For how much emphasis was put on enabling nice tooling during the routing rework, it's being conveniently ignored here. One issue that I also see with this new proposal is that the one-to-one correspondence between the directory tree and the route tree that was emphasized so much during the routing rework is ditched. This is a regression. Plain and simple. To deal with the last remaining piece of the puzzle, I propose that a utility import be added to <script>
import { BlankLayout } from '@sveltejs/kit'
</script>
<BlankLayout>
<slot></slot>
</BlankLayout>
Possible drawbacksI acknowledge that there may be a few drawbacks with this proposal. First, the importing of a Next, and closely related to the previous, could using layouts as if they were components cause confusion about what can and can't be done with them? For example, things like putting layouts inside There's still a lot of open questions about the fine details of implementing a big change like this and whether parts of it are feasible. I hope that Rich and the rest of the team can at least give this some thought, as I think I've been clear about what the advantages of such a system could be, and what the disadvantages are of showing even more of the API into filenames. |
Beta Was this translation helpful? Give feedback.
-
This proposal is ok for me, maybe I can comment on a few things, but folks here have already done it. #6183here, I need a place where I can init i18n, and it should be called globally, after any #6196if I want to have a separate During the discussion for this proposal, don't forget that for each |
Beta Was this translation helpful? Give feedback.
-
Thank you everyone for participating in the discussion! After careful consideration, reading all the alternative proposals and much discussion internally we decided to go with the original proposal, as it - in our opinion - strikes the best balance between simplicity and handling more complex use cases. What became clear from the discussion is that the use cases vary drastically and that it's close to impossible to design an API that satisfies them all in a consistent way that is easy to learn. It also became clear that whatever API we land on, people feel somewhat compelled to use it because "that's what the framework gives you" - even if other means such as composition or a simple if-statement somewhere in your layout would solve the problem more easily. We hope to make it more clear in the docs that you are encouraged to find your own ways if you don't want to use the |
Beta Was this translation helpful? Give feedback.
-
I'm astonished at how fast such a huge change was proposed, discussed, and then implemented. I mean I happen to quite like it — even with a fairly simple use-case (2x authenticated layouts & an unauthenticated layout, all sharing data) named layouts were a pig — but I do feel like these large design changes should somehow be surfaced and dogfooded better. Idk I guess that's difficult when sveltekit is barrelling so fast towards a finalised 1.0 API, but as a user I feel like I JUST did a major refactor I didn't have a chance to think about and I'm gonna have to turn around straight away and go do another one now. I know it's all pre release so I did this to myself, but damn the ride is getting rocky. Bundling some of these huge changes up and communicating them in a more cohesive way to developers would be v helpful EDIT — Just refactored for layout groups, and it made my route structures so much clearer, and auth guards simpler, so I'm a big fan. But regardless the feedback about the rapid succession of poorly communicated breaking changes causing friction in the community stands Still this basic app structure is a thing of beauty 👌🏼
|
Beta Was this translation helpful? Give feedback.
-
When there is a change like this there should be a greater effort to gather input and slowdown to find a more palatable solution for the community over a longer time period . I actually really liked the layout system when their wasn't named layouts and wish there was still an option to use that system for less complicated uses. I generally don't like pushing logic into the filenames and feel like that is the wrong way to go. I would prefer having a another configuration file that specifies the routing grouping as an alternative solution. Can there be a poll on discord / here for this or other controversial proposals in the future? |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
I am okay with the new changes in the routing system, makes my routes easier to reason about because I can group routes to now use the same layout. Excellent work done. FWIW, it would be very helpful if we can version the docs to sync with new updates. I keep the docs opened in multiple tabs only to scroll down to the named-layout section and its gone, I tried updating the package.json with Not everyone follows I really love the work you guys are doing here with a strong emphasis on Keeping It: SvelteKit Simple. Thank you so much for Svelte and SvelteKit are heaven-sent blessings, so invaluable |
Beta Was this translation helpful? Give feedback.
-
Update: The decision has been made, thank you for participating in the discussion!
The sense I've had from recent discussions is that people don't really like how named layouts work. And I kind of agree — a file with a name like
[email protected]
is doing a lot of work, and the inheritance rules (layouts can inherit from sibling layouts indefinitely, but if they don't specify a parent (wait — is it a parent or a sibling?) then they will go one directory higher to continue the search, unless you want them to inherit from the default layout at the current level in which case you can specify@default
, which is a reserved name) are a lot to try and understand.It's a powerful and flexible system, but it's not intuitive, and common tasks (grouping some-but-not-all siblings with a custom layout, or breaking out of the layout hierarchy to the root) are unnecessarily cumbersome.
Beyond that, the fact that it's possible for a directory to contain multiple different layouts adds some unavoidable complexity. For example, because there's no canonical root layout that everything is guaranteed to inherit from, we don't have a place to put code that gets run for every single page, or apply universal CSS. (We often talk about creating a dedicated client entry point — the equivalent of
src/hooks.js
but in the browser — that is responsible for hydrating the app and importing global CSS and e.g. firing analytics events on navigation, but there'd be no need to introduce a new concept like that if we had a root layout.) Implementation-wise, the extra complexity in the codebase is also a source of sadness for me personally.Can we do better?
The two jobs of custom layouts
Fundamentally, there are two reasons to use custom layouts:
/about
and/testimonials
might be 'marketing' pages, while/dashboard
and/item
are 'app' pages and/admin
is neither)<slot />
file), but possibly to something lower down. For example/item/[id]/edit
might need to break out of the app layout or theitem
layout within it.A lot of this can be achieved within a layout itself, by doing this sort of thing...
...but it's less scalable, and only applies to the UI (rather than the
load
functions that apply to different layouts).Here's how we'd achieve the structure above in our current system:
There's a lot going on here: four layouts in
src/routes
, three of which inherit from the base+layout.svelte
(and one of those three,root
, is just a<slot />
since it only exists to give a way to reference the root layout from/item/[id]/edit
).The nice thing about this approach is that the directory structure maps perfectly to the routing structure, but everything else is bad: 'app' and 'marketing' are expressed three different ways (once per route that uses them, plus once in the name of the layout); lexical ordering means that app/marketing pages are interleaved, which in all likelihood doesn't correspond to the placement of shared modules, or the human factor of code organisation (i.e. that the 'marketing' pages are likely owned by a separate team to the 'app' pages); the weird
@root
thing. Making sense of the hierarchy is just really hard.Job 1: groups
An obvious way to solve the grouping problem is with a directory that doesn't add a route segment:
It's subjective, but I find this much more obvious. All the
(app)
and(marketing)
code is co-located (and that would extend to any shared modules or components, which would currently have to go insrc/lib
otherwise they'd clutter up the root directory), and it's easier to trace the 'flow' of layouts from tip to root.Since all this applies to data loading as well as UI, it's also very easy to add an
(authenticated)
guard or similar — just add an(authenticated)/+layout.server.js
file with aload
function that throws anerror
orredirect
if the user isn't logged in.Job 2: breaking out
Technically, it's possible to achieve everything with just groups, by having sibling hierarchies:
...but this is monstrous. Given how often this is necessary, it's worth having a more idiomatic solution. As long as we're using the filesystem to define custom layout hierarchies (on which, see the 'what about' section below), then this necessarily involves adding some syntax to filenames, but it doesn't need to be as much syntax as we currently have.
Currently, you have to declare a layout in some parent directory to act as an 'anchor', which means we need the
-foo
construct. But this is unnecessary, because we already have a perfectly good way of identifying the parent level to which we want to 'ascend' — the segment names themselves.For example if we wanted to use the
c
layout in/a/b/c/d/[e]/+page.svelte
, we don't need to declare a+layout-c
inside thec
directory — we can just... usec
:To ascend straight to the root layout, we can just omit the name altogether —
[email protected]
. So our more realistic example becomes this:src/routes/ ├ (app)/ │ ├ dashboard/+page.svelte │ ├ item/ │ │ ├ [id]/+page.svelte + │ │ └ edit/[email protected] │ │ └ +layout.svelte │ └ +layout.svelte ├ (marketing)/ │ ├ about/+page.svelte │ ├ testimonials/+page.svelte │ └ +layout.svelte ├ admin/+page.svelte └ +layout.svelte
[email protected]
would reset to thewhatever
layout for everything in its subtree.Downsides
The main drawback of this proposal is the way the directory tree no longer maps 1:1 with the routing tree. Finding the code for a specific route becomes very slightly harder. Reasonable people can disagree about how major that is.
A corollary is that it becomes more possible to introduce conflicts (between
(foo)/whatever
and(bar)/whatever
), though the framework can easily throw a helpful error in that case.What about
export const layout = ...
?A common question: why does it need to be expressed in directory and filenames? why can't we having something like this?
One answer is that SvelteKit really needs to be able to resolve the layout hierarchy statically, and with layouts expressed in JavaScript it's impossible to guarantee that. If it can't be determined statically, then SvelteKit needs to load the leaf node (
+page
), then find out which layout it references and load that, and repeat, all the way back to the root one at a time.By constrast, when we know the layout hierarchy statically we can load all the pieces concurrently, resulting in faster apps.
There are other options — we could add a
+config.json
or something. But it's honestly hard to see how that's an improvement.What about existing named layouts?
+layout-name.svelte
etc would no longer exist under this proposal, so it's not additional API, rather it replaces the existing API.Thanks for reading this far! Feedback welcome 🙏
Beta Was this translation helpful? Give feedback.
All reactions