Introduce a feature for bottom-up page-to-layout communication
See original GitHub issueDescribe the problem
Prior to the recent API overhaul (#5748), I used to have a Meta.svelte
component that was rendered by my root layout. This component would read from $page.stuff
— which I had typed in app.d.ts
— and set various page-level head tags such as <title>
, <meta name="description">
and so on based on those stuff
values. Every page would then have to provide this information in its load
function, like so:
export function load() {
return {
stuff: {
meta: {
title: 'Home page',
titleSuffix: 'long',
description: 'Blah blah blah'
}
}
};
}
My app.d.ts
file looked something like:
declare namespace App {
interface Stuff {
meta: {
title: string;
titleSuffix?: 'short' | 'long' | 'none';
description?: string;
};
}
}
And the <Meta>
component:
<script lang="ts">
import { page } from '$app/stores';
const titleSuffixes = new Map<TitleSuffix, string>([
['short', ' | Foo'],
['long', ' | Foo Bar Buzz'],
['none', '']
]);
$: ({
title,
titleSuffix = 'short',
description,
} = $page.stuff.meta);
</script>
<svelte:head>
<title>{title + titleSuffixes.get(titleSuffix)}</title>
{#if description}
<meta name="description" content={description} />
{/if}
</svelte:head>
Now, ever since the API has been re-designed and the stuff
thing has been removed, I’ve been struggling to re-create this properly.
Asking questions on the Discord server and reading this part of the migration guide lead me to think that returning this information as part of the data returned by each load function is apparently the way things like this are meant to be handled now. But I find that this is an almost unacceptable alternative, for two major reasons + a more minor one:
- No type-safety while providing the values in the load functions:
export const load: PageLoad = () => {
return {
meta: {
title: true, // Nothing's preventing me from doing this
titleSuffix: 'somenonsense', // or this
descriptititoitnotintotn: 'Blah blah blah', // or this
}
};
};
- No type-safety while reading the values in the
<Meta>
component
Meta.svelte
:
<script lang="ts">
import { page } from '$app/stores';
</script>
<svelte:head>
<!-- Absolutely no type-safety here, `meta` is `any` -->
<title>{$page.data.meta.title}</title>
</svelte:head>
- These values will be visible from the
+page.svelte
file included as part of itsdata
prop, which is weird since it’s actually none of its business.
meta
isn’t really something that this page is concerned with, so this is slightly awkward.
This (particularly the lack of type-safety) clearly yields a drastically poorer developer experience compared to the previous API. I sense that not enough thought has been put into this particular requirement when re-designing the API, namely bottom-up communication between pages and layouts. Page data isn’t really fit for this use case at all.
Describe the proposed solution
I don’t have a clear-cut proposal here, the general idea is that perhaps you could consider introducing a new construct designed specifically for bottom-up page-to-layout communication, in order to properly accommodate use cases like this, which are by no means uncommon or unusual, or niche. It actually gets more complex in a real-world app where there are typically multiple levels of layouts, and each of them receives a different set of configurations/settings; which is why I believe this is something that deserves a dedicated feature, so to speak.
Importance
crucial
Additional Information
Please don’t just hand wave this away, thanks. I know it’s annoying that literally dozens of issues get created on this repo every single day and naturally it’s almost impossible to give each and every single one of them a lot of attention, but this one is a real problem, I think, and one that is in need of a response from your side.
And tell me if I’m missing something, because I certainly raised an eyebrow while trying to do this but failing to find a satisfying solution, so it’s possible that I’m unaware of something here.
Issue Analytics
- State:
- Created a year ago
- Reactions:3
- Comments:42 (36 by maintainers)
One thought that occurs to me: in the same way we used to have
App.Stuff
, we could have anApp.PageData
type that everyPageLoad
function is required to return, then we could use that same type for$page.data
:A fancier version would allow a
PageLoad
function not to returntitle
if a parent layout already did (I think that’s possible), so that a group of pages could share atitle
.But a layout (whether it’s the default layout or a nested or reset one) could return it on behalf of its section of pages, right? It doesn’t make sense for
title
in the example, but for some other shared property, it could (example: stylizing various sections of a website with acolor
, like I do for my school notes).