I wrote a Sapper app with session management following the RealWorld example:
polka()
.use(bodyParser.json())
.use(session({
name: 'kidways-app',
secret: 'conduit',
resave: false,
saveUninitialized: true,
cookie: {
maxAge: 31536000
},
store: new FileStore({
path: 'data/sessions',
})
}))
.use(
compression({ threshold: 0 }),
sirv('static', { dev }),
pdfMiddleware,
sapper.middleware({
session: req => ({
token: req.session && req.session.token
})
})
)
.listen(PORT, err => {
if (err) console.log('error', err);
});
Then on my _layout.sevlte
:
<script context="module">
export async function preload({ query }, session) {
console.log('preload', session)
return {
// ...
};
}
</script>
<script>
import { onMount, createEventDispatcher } from 'svelte';
import { Splash } from 'project-components';
import * as sapper from '@sapper/app';
import { user } from '../stores';
import client from '../feathers';
const { session } = sapper.stores();
onMount(async () => {
try {
await client.reAuthenticate();
const auth = await client.get('authentication');
user.set(auth.user);
$session.token = 'test';
} catch (e) {
} finally {
loaded = true;
}
});
console.log($session)
</script>
<h1>{$session.token}</h1>
This work on client side rendering, but the token is still undefined on preload, making my SSR template rendering broken.
What did I missed?
Sapper is the companion component framework to Svelte that helps you build larger and more complex apps in a fast and efficient way. In this modern age, building a web app is a fairly complex endeavor, with code splitting, data management, performance optimizations, etc.
If you are using Sapper as an authentication/authorization server, you can use session middleware such as express-session in your app/server.js in order to maintain user sessions. If the user navigated to /blog/some-invalid-slug, we would want to render a 404 Not Found page. We can do that with this.error:
Is there an idiomatic Svelte / Sapper way to guarantee code only runs client-side, when it has access to cookies? way to guarantee code only runs client-side JS files send from server are runned at client side, cookies are send to server with request - this is all you need. In Svelte / Sapper, the code also runs (and fails) server-side.
The session function may return a Promise (or, equivalently, be async ). Note that if session returns a Promise (or is async ), it will be re-awaited for on every server-rendered page route. Sapper uses code splitting to break your app into small chunks (one per route), ensuring fast startup times.
When a page renders, session
is populated according to the return value of the function you specified here:
sapper.middleware({
session: req => ({
token: req.session && req.session.token
})
})
So while the client may have an up-to-date token, it won't take effect on page reload unless you somehow persist the token to the server in such a way that the session middleware knows about it.
Typically you'd achieve this by having a server route, like routes/auth/token.js
or something...
export function post(req, res) {
req.session.token = req.body.token;
res.writeHead(200, {
'Content-Type': 'application/json'
});
res.end();
}
...and posting the token from the client:
onMount(async () => {
try {
await client.reAuthenticate();
const auth = await client.get('authentication');
user.set(auth.user);
await fetch(`auth/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ token })
});
// writing to the session store on the client means
// it's immediately available to the rest of the app,
// without needing to reload the page
$session.token = 'test';
} catch (e) {
} finally {
loaded = true;
}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With