Skip to content
This repository has been archived by the owner on Jan 11, 2023. It is now read-only.

Svelte 3 equivalent of Sapper's store #552

Closed
Rich-Harris opened this issue Jan 29, 2019 · 2 comments
Closed

Svelte 3 equivalent of Sapper's store #552

Rich-Harris opened this issue Jan 29, 2019 · 2 comments

Comments

@Rich-Harris
Copy link
Member

Currently, with Svelte 2, you can pass data from server to client like so:

// server.js
app.use(sapper.middleware({
  store: req => ({
    user: req.session && req.session.user
  })
})
// client.js
sapper.start({
  target,
  store: data => new Store(data)
})

Behind the scenes, Sapper handles [de]serialization.

This is the accepted way to handle problems related to authentication, because user data has a couple of important characteristics:

  • You really don't want to accidentally leak it between two sessions on the same server, and generating the store on a per-request basis makes that very unlikely
  • It's often used in lots of different places in your app, so a global store makes sense.

But Svelte 3 doesn't have global stores that are passed around in quite the same way. One option would be to generate props, and rely on the developer to pass them around as necessary (including via layout components). This would be cumbersome, and would encourage developers to populate stores from inside components, which makes accidental data leakage significantly more likely.

A second option is to create the store on the generated app:

// generated code
import { writable } from 'svelte/store';
export const store = writable(__SAPPER__.store); // serialized and included on the page
// anywhere inside your app
<script>
  import { store } as app from '@sapper/app'; // see #551
</script>

{#if $store.user}
  <h1>Hello {$store.user.name}!</h1>
{:else}
  <p>please <a href="login">log in</a></p>
{/if}

(See #551 for an explanation of @sapper/app.)

Does that make sense? Is store the right name? (session?)

@Rich-Harris
Copy link
Member Author

Just realised this doesn't actually work. If store is just something exported by the app, there's no way to prevent leakage.

Instead, it needs to be tied to rendering, which means we need to use the context API. Sapper needs to provide a top level component that sets the store as context for the rest of the app. You would therefore only be able to access it during initialisation, which means you couldn't do it inside a setTimeout and get someone else's session by accident:

<script>
  import * as app from '@sapper/app';

  // this works...
  const store = app.session();

  // but this would fail
  setTimeout(() => {
    const store = app.session();
  });
</script>

(app.session uses getContext under the hood.)

Rich-Harris added a commit that referenced this issue Feb 3, 2019
@Rich-Harris
Copy link
Member Author

Implemented on current master, alongside #554 which makes it much harder to accidentally keep logged-in state visible after a client-side logout

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

No branches or pull requests

1 participant