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

SvelteKit SSE Example #12

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions examples/sveltekit-sse/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example

# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock
15 changes: 15 additions & 0 deletions examples/sveltekit-sse/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module.exports = {
root: true,
extends: ['eslint:recommended', 'prettier'],
plugins: ['svelte3'],
overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }],
parserOptions: {
sourceType: 'module',
ecmaVersion: 2020
},
env: {
browser: true,
es2017: true,
node: true
}
};
10 changes: 10 additions & 0 deletions examples/sveltekit-sse/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
1 change: 1 addition & 0 deletions examples/sveltekit-sse/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
engine-strict=true
13 changes: 13 additions & 0 deletions examples/sveltekit-sse/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example

# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock
9 changes: 9 additions & 0 deletions examples/sveltekit-sse/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"useTabs": true,
"singleQuote": true,
"trailingComma": "none",
"printWidth": 100,
"plugins": ["prettier-plugin-svelte"],
"pluginSearchDirs": ["."],
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
}
13 changes: 13 additions & 0 deletions examples/sveltekit-sse/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# SvelteKit SSE Example

A simple SvelteKit example that implements the SSE protocol and works with multiple users. Each user is assigned a cookie with a random ID using `crypto.randomUUID()` to identify each client and limit the number of connections.

## `lib/sse-manager.server.js`

This file keeps track of all `ReadableStream`s/SSE connections and allows you to emit events to all or only specific clients. The code is portable and works in all JavaScript envionments that accept `ReadableStream`s as HTTP responses including SvelteKit, Deno and Bun.

## `lib/sse-store.js`

This file contains a custom store that opens the SSE connection, listens for events emitted from the server and updates the store's value accordingly.

**Note:** SSE requires a contionously open HTTP connection so in order to use `sse-manager.server.js` it needs to be deployed to Edge functions, a server using `adapter-node` or as a separate Deno or Bun app. Serverless functions have an execution limit of only a few seconds and therefore don't work.
17 changes: 17 additions & 0 deletions examples/sveltekit-sse/jsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true
}
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias and https://kit.svelte.dev/docs/configuration#files
//
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
// from the referenced tsconfig.json - TypeScript does not merge them in
}
28 changes: 28 additions & 0 deletions examples/sveltekit-sse/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "sveltekit-sse",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json --watch",
"lint": "prettier --plugin-search-dir . --check . && eslint .",
"format": "prettier --plugin-search-dir . --write ."
},
"devDependencies": {
"@sveltejs/adapter-auto": "^2.0.0",
"@sveltejs/kit": "^1.15.7",
"eslint": "^8.38.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-svelte3": "^4.0.0",
"prettier": "^2.8.7",
"prettier-plugin-svelte": "^2.10.0",
"svelte": "^3.58.0",
"svelte-check": "^3.2.0",
"typescript": "^5.0.4",
"vite": "^4.3.0"
},
"type": "module"
}
12 changes: 12 additions & 0 deletions examples/sveltekit-sse/src/app.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// See https://kit.svelte.dev/docs/types#app
// for information about these interfaces
declare global {
namespace App {
// interface Error {}
// interface Locals {}
// interface PageData {}
// interface Platform {}
}
}

export {};
12 changes: 12 additions & 0 deletions examples/sveltekit-sse/src/app.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width" />
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>
13 changes: 13 additions & 0 deletions examples/sveltekit-sse/src/hooks.server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
let id = event.cookies.get('id');

if (!id) {
id = crypto.randomUUID();
event.cookies.set('id', id);
}

event.locals.id = id;

return await resolve(event);
}
106 changes: 106 additions & 0 deletions examples/sveltekit-sse/src/lib/global.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/* RESET */

*,
*::before,
*::after {
box-sizing: border-box;
padding: 0;
margin: 0;
}

html,
body {
height: 100%;
font-family: sans-serif;
}

html:focus-within {
scroll-behavior: smooth;
}

body {
line-height: 1.5;
}

a:not([class]) {
text-decoration-skip-ink: auto;
}

img,
picture,
video,
canvas {
display: block;
max-width: 100%;
}

input,
button,
textarea,
select,
input[type='file']::file-selector-button {
font: inherit;
}

label,
textarea,
progress,
input:where(
[type='email'],
[type='password'],
[type='search'],
[type='tel'],
[type='text'],
[type='url'],
[type='file']
) {
display: block;
width: 100%;
}

textarea {
box-sizing: content-box;
min-height: 5em;
resize: block;
resize: vertical;
}

/* THEME */

h1 {
margin-block-start: 3rem;
margin-block-end: 2rem;
}

h2,
h3 {
margin-block-start: 2rem;
margin-block-end: 1rem;
}

label {
font-weight: 700;
margin-block-end: 0.25rem;
}

button,
input[type='file']::file-selector-button {
padding-inline: 0.5rem;
padding-block: 0.2rem;
cursor: pointer;
}

button:hover {
filter: brightness(1.1);
}

button.--loading {
cursor: wait;
opacity: 0.6;
}

.box {
padding: 1rem;
border-radius: 7px;
background-color: hsla(0, 0%, 0%, 0.07);
}
Loading