Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Page metadata #269

Closed
Conduitry opened this issue Dec 14, 2020 · 15 comments · Fixed by #3252
Closed

Page metadata #269

Conduitry opened this issue Dec 14, 2020 · 15 comments · Fixed by #3252
Labels
feature request New feature or request p1-important SvelteKit cannot be used by a large number of people, basic functionality is missing, etc.
Milestone

Comments

@Conduitry
Copy link
Member

Conduitry commented Dec 14, 2020

Is your feature request related to a problem? Please describe.
Components that are used in layouts currently don't have access to which route they're being used on. The $page store tells us the underlying path and the params that have been extracted from that path, but doesn't tell us anything about which route those params have meaning in.

When making a navbar in Sapper, I generally have to re-analyze $page.path with regexes or string comparisons or whatever in order to tell which page I'm on and what state the navbar should be in.

Describe the solution you'd like
Since the framework has already decided which route this request maps to, it can expose this information in the $page store. The most immediately obvious way to me for this to be handled would be for the relative path to the .svelte file that is the page route be included as a string in (say) $page.route.

Describe alternatives you've considered
If we didn't want the inelegance or fragility of exposing file paths as strings, would be to let each page component expose - in some way - a user-specified key that Kit doesn't do anything with apart from exposing in the $page store. This could be a separate module context export, or it could be another value in the load response, or maybe something else. This was also suggested in #1459

How important is this feature to you?
It'd be nice to have. That my code needs to re-figure out something about what page I'm on that the framework has already determined and then kept for itself is irritating.

Additional context
None that I can think of right now.

@Conduitry Conduitry added the feature request New feature or request label Dec 14, 2020
@Conduitry
Copy link
Member Author

This would be more of an issue with route fallthrough (#548) because there's no longer necessarily a quick way to tell routes apart looking just at their paths.

@alteredorange
Copy link

I think this is important, because it looks like sveltekit doesn't export segment like sapper did. (At least segment is always undefined when I export it from $layout). Currently I'm using $page.path.substring(1) for all my route needs, but it would be great if there was an actual route param, as I'm not sure the substring works with all edge cases.

@Wolfr
Copy link

Wolfr commented Apr 4, 2021

@alteredorange This code helped me implement a simple selected state in my SvelteKit demo app. Thank you.

@Brawl345
Copy link

Brawl345 commented Apr 4, 2021

Using $page.path works, but I want to e.g. see $error there when I'm on an error page. Currently, there is no way to do that afaik? Next.js has router.route for example

@Conduitry
Copy link
Member Author

Exposing error information has its own issue, #598.

@gterras
Copy link

gterras commented May 15, 2021

Apologies if I'm missing something but from my understanding:

The ability to get the relative path to the .svelte file is crucial and the only way to properly generate hrefs without relying on any kind of hardcoded values (like current folder depth or name). See this common use case (caps for clarity):

│── index.svelte
│── layout.svelte
├── CATS
│   ├── layout.svelte
│   └── SIAMESE
│       ├── layout.svelte
│       ├── GENERAL
│       │   └── index.svelte
│       ├── DETAILS
│       │   └── index.svelte
│       └── PICTURES
│           └── index.svelte
│   └── PERSIAN
│       ├── layout.svelte
│       ├── PRESENTATION
│       │   └── index.svelte
│       ├── DETAILS
│       │   └── index.svelte
│       └── PICTURES
│           └── index.svelte
├── DOGS
│   └── ...
├── TURTLES
│   └── ...

Say each layout needs to display links related to its current level, ending up with 3 levels of menus:

CATS | DOGS | TURTLES
   SIAMESE | PERSIAN
      GENERAL | DETAILS | PICTURES

$page.path having the same value in each of the layout it makes it a bit cumbersome to generate link items or hrefs. Here is what you probably end up doing for each level of layout :

// specific to this route depth level, risky
const depth = 2

// awkward
const baseUrl = $page.path.split('/').slice(0, depth + 1).join('/')  
$: active = $page.path.split('/')[depth + 1] 

const items = ['PRESENTATION','DETAILS','PICTURES' ].map(item => ({
name: item, 
href: baseUrl + '/' + item, 
}))

Which also inevitably leads to the creation of a helper store. With $page.relative this could be simplified to:

// Elegant

$: active = $page.relative.split('/').pop()

const items = ['PRESENTATION','DETAILS','PICTURES' ].map(item => ({
name: item, 
href: $page.relative + '/' + item, 
}))

In addition a $page.relativeGlob would be very helpful to allow completely removing hardcodes from layouts when the slug is the same as the label (although I don't have too much hope for this one):

// Mind blowing

$: active = $page.segment

const items =  $page.relativeGlob.map(item => ({
name: item, 
href: $page.relative + '/' + item, 
}))

@benmccann benmccann added this to the 1.0 milestone May 17, 2021
@benmccann
Copy link
Member

@gterras could you do something like that with Vite's import.meta.glob?

https://github.com/babichjacob/university-website/blob/84b5e7ff44550910550a3c809ccb9f1402df301b/README.md

@benmccann
Copy link
Member

benmccann commented Aug 3, 2021

Automatically putting the file path in the $page store would increase the bundle size.

#1459 describes this issue in a different way, which is wanting a way to set a variable in the leaf, which is made available to the layout (e.g. menuCategory = 'animals')

Would it be possible to use a store for this and set the store value on each page? Would SvelteKit support even be required for that?

@benmccann benmccann removed this from the 1.0 milestone Aug 3, 2021
@Conduitry
Copy link
Member Author

Having a page component update some state that's read by a component in a higher-level layout component sounds like it would likely not work well with SSR.

I take your point about exposing file paths in the $page store (which always felt like an ugly API to me anyway). Having some freeform metadata that's exposed either as a module export from the page component or as something returned by the load function and which is then exposed on the $page store seems like a tidy way to do this and like it would have only a very small effect on people who aren't using the feature.

@benmccann
Copy link
Member

Having a page component update some state that's read by a component in a higher-level layout component sounds like it would likely not work well with SSR.

Despite doing a lot on SvelteKit, I've still done little with Svelte itself. Do store updates not work in SSR? The Svelte docs don't mention any such restriction, so it's not clear to me what the issue might be

@Conduitry
Copy link
Member Author

I haven't tried this particular case, but in general, SSR'd results that depend on state that's updating during the rendering of the component are a best-effort, no-promises type of thing. We're building the HTML string as we go in SSR - we don't instantiate a whole DOM tree and then wait for all of the state to settle and then serialize it (which would be a lot more expensive).

Store updates within a single component probably mostly work in SSR (as long as the updates happen synchronously), but it's using them to communicate between components that's making me doubtful.

Even if this worked in Svelte, where would the store live? It couldn't be its own external file, because then that would be shared by all visitors to the site on the server side.

@benmccann
Copy link
Member

benmccann commented Aug 5, 2021

Even if this worked in Svelte, where would the store live?

Per-request state seems like a problem we should have an answer to. Right now, you could put it on locals on the server-side for instance. Then you could transmit it to the client in session and instantiate a store with it. That's a little complicated and messy, but it's a problem I've seen people face quite a few times in other contexts

That being said, your suggestion on the API sounds reasonable. How about something like this:

I don't know a good name for this but something like this only on the page (i.e. leaf node. not the layouts):

export const pageData = ({ request }) => {
    ...
}

And then whatever it returned would be made available in load as a parameter:

export const load = ({ pageData}) => {
    ....
}

I think that could potentially be better than returning something from `load` because the layout `load` functions would then have access to the leaf node data which would give you a way to pass that data as props

@benmccann benmccann added this to the 1.0 milestone Aug 9, 2021
@benmccann benmccann added the p1-important SvelteKit cannot be used by a large number of people, basic functionality is missing, etc. label Aug 9, 2021
@benmccann benmccann changed the title Some way to expose in $page store which route we're on Page metadata Oct 22, 2021
@didier
Copy link

didier commented Nov 15, 2021

Would it be possible to implement an API similar to https://github.com/didier/sveo? I'd love to help where possible.

<script context="module">
  // /about.svelte
  export const metadata = {
    title: 'Hello world',
    description: 'Have a wonderful day.'
  }
</script>
<script context="module">
  // /__layout.svelte
  export const load = async ({ metadata }) => {
    // The metadata from the page component
    const { title, description } = metadata

    return {
      props: {
        title,
        description
      }
    }
  }
</script>

This would make SEO stuff a lot easier, since we can define titles and other data on a page level and have all the meta tags handled by the layout component.

@jchanes04
Copy link

I believe adding this functionality would also make it easier to make sveltekit websites work well with link previews, for similar reasons as SEO. I'm not completely familiar with how different websites/messaging services generate link previews, but I've run into a few issues in the past with them (page titles including undefined, for example).

@benmccann
Copy link
Member

Rich has a suggestion today: allow specifying stuff in leaf nodes just like you can do with layouts and then make it available in the page store.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request New feature or request p1-important SvelteKit cannot be used by a large number of people, basic functionality is missing, etc.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants