question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

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

See original GitHub issue

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.

Issue Analytics

  • State:closed
  • Created a year ago
  • Reactions:3
  • Comments:42 (36 by maintainers)

github_iconTop GitHub Comments

4reactions
Rich-Harriscommented, Aug 18, 2022

One thought that occurs to me: in the same way we used to have App.Stuff, we could have an App.PageData type that every PageLoad function is required to return, then we could use that same type for $page.data:

// src/app.d.ts
declare namespace App {
  interface PageData {
    title: string;
  }
}
// $types.d.ts
export type PageLoad = Kit.PageLoad<Params, InputData, App.PageData & Record<string, any>>;
import type { PageLoad } from './$types';

export const load: PageLoad = () => ({
  title: `if this is missing, it'll cause red squigglies`,
  other: {
    stuff: 'yay'
  }
});
// types/ambient.d.ts inside Kit
export interface Page<Params extends Record<string, string> = Record<string, string>> {
  url: URL;
  params: Params;
  routeId: string | null;
  status: number;
  error: HttpError | Error | null;
-  data: Record<string, any>;
+  data: App.PageData & Record<string, any>;
}

A fancier version would allow a PageLoad function not to return title if a parent layout already did (I think that’s possible), so that a group of pages could share a title.

2reactions
babichjacobcommented, Aug 18, 2022
<svelte:head>
 <title>{$page.data.title}<title>
</svelte:head>

For that to work, every PageLoad function must return title.

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 a color, like I do for my school notes).

Read more comments on GitHub >

github_iconTop Results From Across the Web

Top-Down vs. Bottom-Up Approach - Smartsheet
In comparison, the bottom-up style of communication features a decision-making process that gives the entire staff a voice in company goals.
Read more >
Bottom-Up Communication Vs. Top-Down Management
Break down the communication silo at your organization with a bottom-up, employee-inclusive communication style. Miscommunication can cause some ...
Read more >
Internal Communication Tool for Bottom-Up Leadership
Learn how an internal communication tool can foster bottom-up communication in your organization. Click here to read the full article.
Read more >
Communication Technology 101: Bottom-Up Approach ...
The bottom-up approach is the opposite of a top-down management style. Learn their differences to help you choose which to apply for your...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found