Skip to content

Add layout endpoints #4274

@Rich-Harris

Description

@Rich-Harris

Describe the problem

Page endpoints have been a popular addition to SvelteKit, despite a few lingering bugs. Since before they landed, people have (quite reasonably) been asking why we don't have layout endpoints.

The biggest reason, frivolous as it might sound, is naming. 'Layout' is very much a UI concept, and so a __layout.js file that is solely concerned with loading data feels a bit weird.

Describe the proposed solution

As part of a wider overhaul of routing (follow-up issue to come, which will address pathless routes and granular layout resets) I propose changing __layout.svelte to __section.svelte and adding a corresponding __section.js (or .ts, etc) endpoint. 'Section' feels like a sufficiently agnostic word — it leans towards UI terminology, but it doesn't feel weird to talk about a 'section endpoint', as in 'the endpoint for the blog section' or the admin section or whatever.

Just as page endpoints expose their data as a virtual child __data.json route, section data will need to be exposed, perhaps by appending __section.json (i.e. src/routes/foo/__section.js is exposed as /foo/__section.json).

One major difference between section endpoints and page endpoints: since sections don't 'own' a specific URL, it doesn't make sense to be able to POST to them etc. I'd therefore argue that non-get handlers should be forbidden in section endpoints.

Alternatives considered

Other frameworks like Nuxt and Remix think about nested routes differently to how SvelteKit does it. Consider a route like /settings/notifications/email where email is nested within the notifications section, which is nested inside the settings section.

In SvelteKit the filesystem would look like this:

routes/
├── settings/
│   ├── billing/
│   ├── └── [files]
│   ├── notifications/
│   ├── ├── desktop.{js,svelte}
│   ├── ├── email.{js,svelte}
│   ├── └── __section.{js,svelte}
│   └── __section.{js,svelte}

Instead of having something like __section, Nuxt and Remix use a filename with the same name as the directory:

routes/
├── settings/
│   ├── billing/
│   ├── └── [files]
│   ├── notifications/
│   ├── ├── desktop.js (or desktop.vue, in Nuxt's case)
│   ├── └── email.js
│   ├── billing.js
│   └── notifications.js
├── settings.js

(In both cases, /settings and /settings/notifications routes can be added with index files.)

I don't think one of these approaches is unambiguously better than the other, but we can enumerate some pros and cons of the SvelteKit approach. Pros:

  • Things are appropriately colocated — all the notifications-related code lives together, rather than being split between notifications/ and notifications.{js,svelte}
  • Renaming 'settings' to 'preferences' happens in one place, not two
  • If you expand a folder like settings in your editor, the breadth of the folder is capped at n+2 rather than 3n where n is the number of nested sections (i.e. billing/, notifications/, __section.js and __section.svelte rather than billing/, notifications/, billing.js, billing.svelte, notifications.js and notifications.svelte)
  • It's arguably more explicit
  • If you needed /settings to have a completely different layout than /settings/* for some reason, it's easy — you can have routes/settings.{js,svelte}. If that file is instead used for layout, /settings/index.{js,svelte} must inherit from it unless you add a new convention for exempting it, like Remix's routes/settings.index.js (I've also seen routes/settings+index.js), which feels less than 100% intuitive to me

Cons:

  • The Nuxt/Remix convention is arguably more aesthetically pleasing than __section. Though as an aside, we're using the __ prefix convention anyway for __error.svelte, and we'll likely add directory-scoped __middleware.js at some point
  • settings.js is a more descriptive basename than __section.js
  • settings.js and settings/notifications.js lend themselves more easily to endpoint URLs (though we would need a way to disambiguate between settings.js and settings/index.js endpoint URLs in any case)
  • We're going against the grain. (Same as it ever was.)

In summary, I lean towards the __section proposal, but I would be curious to hear any arguments in favour of (or against) a more Nuxty/Remixy approach that I haven't considered here.

Importance

would make my life easier

Additional Information

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions