Skip to content

Introduce a feature for bottom-up page-to-layout communication #5951

@aradalvand

Description

@aradalvand

Describe 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:

  1. 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 
    }
  };
};
  1. 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>
  1. These values will be visible from the +page.svelte file included as part of its data prop, which is weird since it's actually none of its business.

image
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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions