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

"Stuff" not present with Shadow Endpoints #3860

Closed
isaac-mcfadyen opened this issue Feb 11, 2022 · 9 comments
Closed

"Stuff" not present with Shadow Endpoints #3860

isaac-mcfadyen opened this issue Feb 11, 2022 · 9 comments

Comments

@isaac-mcfadyen
Copy link
Contributor

isaac-mcfadyen commented Feb 11, 2022

Describe the problem

With the recent advent of shadow endpoints #3532, it is now possible to move all database requests or other external loading to the .ts or .js file.

However:

  • Shadow endpoints do not have an output of stuff like load functions.
  • Therefore, a load function is still required when wanting to pass stuff to __layout.svelte files.
  • While this doesn't seem like a big deal, it is. When every page needs to pass stuff as an output - for example, for <meta> tags - then the entire point of shadow endpoints is defeated.

Describe the proposed solution

A possible solution could be to add an export of stuff to endpoint files. The complexity of this is unknown.

Alternatives considered

Require the user to provide a redundant load function on every page. However, this is suboptimal.

Importance

Would make my life a lot easier!

Additional Information

*crickets chirp*

@babichjacob
Copy link
Member

When every page needs to pass stuff as an output - for example, for tags - then the entire point of shadow endpoints is defeated.

Are you sure it's that extreme?

The original issue for shadow endpoints includes an example of writing a load function easier than before when you can't get away with not having a load function:

We could get the best of both worlds by feeding the props from the shadow endpoint into load ...

For this situation, it'd be like:

<script context="module">
  /** @type {import('@sveltejs/kit').Load */
  export async function load({ props }) {
    return {
      props,
      stuff: { ... }, 
    }
  }
</script>

It is still the case, though, that you can't send something from stuff to a shadow endpoint, but that isn't what this issue explains.

@isaac-mcfadyen
Copy link
Contributor Author

It's not that extreme, no 🙂.

But even that simple load extends every .svelte file by 10 lines, so for large sites it would add a lot of redundant code.

Really, my opinion was that this is something that should be explored, and if it's not feasable, discarded. But if it is feasable then it would reduce redundant code and increase DX.

@CaptainCodeman
Copy link
Contributor

I'm finding my locals-to-stuff populating tends to happen in the root __layout, and from then on I access things via the $page store stuff property. It's usually a 'site context' kind of thing. The typing for stuff tends to re-enforce that it's an app level definition (I know, it doesn't have to be - things could be set as optional and used at different levels).

It would be "nice" to not need to have anything in __layout to do that root level population, but without it ... meh, I think I'll live.

Mentally, I would prefer it to be part of hooks, it feels similar to the getSession function in what it does / how I use it.

@isaac-mcfadyen
Copy link
Contributor Author

Yes, that works very well for passing from the __layout.svelte to the pages.

I use stuff to pass the other way (pages to the layout) to populate <meta> tags, so this issue was mainly because I was thinking about that.

@rmunn
Copy link
Contributor

rmunn commented Feb 22, 2022

Edit: Ignore the below; as #3860 (comment) points out, I misunderstood what's being asked for.

I agree that it would be nice if shadow endpoints could be as equivalent as possible to load() functions, including having access to stuff passed down from layouts higher in the component tree. But there are significant technical challenges involved, since layout code runs in the browser while shadow endpoints run on the server. Unless the page is being server-side rendered, that means that before the endpoint could run and access stuff, the user's browser would have to submit a POST to some special server-side URL (which would have to be decided on and documented) in order to supply the endpoint with the data that should be in stuff. And some adapters might not be able to allow that at all. For example, an adapter that converts Svelte-Kit endpoints to serverless lambda functions running on services like Vercel or Netlify might not be able to create a URL for supplying stuff to the function, depending on how the provider's API works. (I'm not familiar enough with Vercel's or Netlify's APIs to know for sure whether it would be possible).

So I'd say that while this is a nice idea, it might be impossible (or at least infeasible) to do, and it will probably be better to design your use of stuff so that only client-side code needs it, while shadow endpoints can get by without it.

@isaac-mcfadyen
Copy link
Contributor Author

I think there might be some misunderstanding here.

Both load() functions and shadow endpoints run during SSR. Currently, the load() function is able to return stuff, which makes it visible to client-side code in the layout (one-way, server passes to client).

My suggestion was bringing the shadow endpoints to parity there; shadow endpoints should also be able to return stuff and have it pass to the client (one-way, server passes to client).

I wasn't suggesting that shadow endpoints should have stuff as an input; I agree, that would be too technologically unfeasable.

@rmunn
Copy link
Contributor

rmunn commented Feb 22, 2022

Yes, I missed that you specified output in your description. So the only technical challenge would be merging any stuff from layouts (client-side) with stuff passed from shadow endpoints to the client. Which should be pretty straightforward.

I'll update my comment to mention that it was a misunderstanding.

@Rich-Harris
Copy link
Member

The challenge here is that stuff can contain non-serializable things (like functions), and introducing caveats like 'you can use stuff in endpoints but only if it's serializable' starts to get a bit muddy.

For what it's worth you could rewrite this...

<script context="module">
  /** @type {import('@sveltejs/kit').Load */
  export async function load({ props }) {
    return {
      props,
      stuff: { ... }, 
    }
  }
</script>

...as this:

<script context="module">
  import { add_stuff } from '$lib/stuff';
  export const load = add_stuff(props => ({
    title: props.title
  }));
</script>

At that point it's only a tiny bit more code than adding stuff to the endpoint, but without any of those caveats.

@isaac-mcfadyen
Copy link
Contributor Author

Absolutely, that makes sense. I'm going to close this Issue then and we can reopen in the future if anything changes/there are any other considerations to consider.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants