Svelte App-Level Design Patterns¶
Routing with Svelte¶
to be written
- A map for an app: what is routing
- Different approaches
- XML-stylee: svelte-routing
- Express-stylee: navaid
- FS based routing: routify
Further Links¶
- Routify (with Routify Starter)
- svelte-routing
Authentication with Svelte¶
Figuring out how to authenticate with Svelte can be tricky business. The official docs for Sapper, the Server-Side Rendering platform designed for Svelte, recognize that session management should be handled by some other service such as express-session, but you are not limited to using any backend with Svelte. Moreover, Sapper does not have native support for persistent sessions (as of April 2020).
Your best options might be to offload session management from Svelte to some other web server that is configured to use HTTPS. In many cases, your clients will want to authenticate using a modern web browser, and most modern web browsers implement strong security regulations over how data gets transferred between a server and a client. During development, you might see this error: "Reason: CORS header 'Access-Control-Allow-Origin' missing", and if you do then it may be worth a few minutes to read up on "Dealing with CORS Errors in Svelte".
Method 1: JSON Fetch using a POST method (same-origin cors headers)
While Svelte may not necessary require an asynchronous authentication method, your application's performance could benefit from trying to use one. It is generally accepted that POST
methods are the way to go, since they do not append sensitive data after the request URI. In this example, we incorporate writable stores (for saving the auth server's response), reactive statements for building the data body of the POST request, and specialized Svelte tags {#await <promise>}
, {:then <awaited response>}
, {:catch <some error>}
to render a different HTML tag at each stage of the authentication request.
It is important to note that this example includes preventDefault
to prevent the runtime from making an HTTP request at the instant when the form element gets created: <form on:submit|preventDefault={submitHandler}>
.
<script>
import { session } from './session.js';
/* session.js:
* ===========
* import { writable } from 'svelte/store';
* export const session = writable({ data: "" })
*/
// Alternatively, you could write:
// export const AUTH_SERVER_URL;
// instead of:
// const AUTH_SERVER_URL = "...";
// to set the destination using the props spread
const AUTH_SERVER_URL = "https://authserverurl.com/api/login";
let email = "";
let password = "";
let combined;
let data;
$: combined = {email: email, password: password};
$: if(data) {
$session.data = data;
}
async function authenticate() {
// Gathered from: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
let response = await fetch(AUTH_SERVER_URL, {
method: 'post',
mode: 'cors', // no-cors, *cors, same-origin,
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json'
// 'Content-Type': 'application/x-www-form-urlencoded',
},
redirect: 'follow', // manual, *follow, error
referrerPolicy: 'no-referrer', // no-referrer, *client
body: JSON.stringify(combined) // body data type must match "Content-Type" header
});
// One additional option is to use:
// ... = await response.json();
// But since we're printing out the response in an HTML element,
// it is convenient to await the `.text()` promise.
let text = await response.text();
// This next line is verbose, but it's meant to demonstrate
// what happens when we want to use a reactive value change
// to bind our new information using `$: if(data) {...}`
let data = text;
return text;
}
function submitHandler() {
/* This promise needs to be awaited somewhere --
* either in the HTML body via `{#await}` tags,
* in a `<script>` tag, or in an imported `.js` module.
*/
result = authenticate();
// Clear out the data fields
email = "";
password = "";
}
</script>
<div>
<form on:submit|preventDefault={submitHandler}>
<input type="text" bind:value={email}>
<input type="password" bind:value={password}>
<button>Submit</button>
</form>
</div>
<div>
{#if result===undefined}
<p />
{:else}
{#await result}
<div><span>Logging in...</span></div>
{:then value}
<div><span>{value}</span></div>
{:catch error}
<div><span>{error.message}</span></div>
{/await}
{/if}
</div>
Server Side Rendering¶
some content
- What is it
- What does the API look like
- building an SSR component
- hydrating an SSR cmponent with a client build
- building a simple express-based SSR server thing
- putting it all together