Skip to content

EventSource support inside Endpoints #1573

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

Closed
kjmph opened this issue May 28, 2021 · 2 comments
Closed

EventSource support inside Endpoints #1573

kjmph opened this issue May 28, 2021 · 2 comments

Comments

@kjmph
Copy link

kjmph commented May 28, 2021

One of the missing features holding me back from SvelteKit as opposed to Next.js is the ability to have an endpoint that acts as a text/event-stream also known as an EventSource. However, SvelteKit has a very appealing endpoint design, and it would be great to have it support Event Streams.

It would be great to have this support baked in to SvelteKit, and one design that I believe is appealing is to return a body in the endpoint that is an async generator function. SvelteKit can instantiate that as an async generator and consume the iterator until it has exited, or the client has disconnect, which ever comes first.

I believe the adapter design for SvelteKit does cause a problem in that this feature is only available where long running request processing can be enabled. There are a few caveats with load balancers and serverless that will cause problems keeping the EventSource open. Yet, this proposal doesn't require SvelteKit to be involved in processing the event stream, and all the client-side retry logic will work flawlessly.

Please see a proposed experimental branch here:
https://github.com/sveltejs/kit/compare/master...kjmph:feature/event-source?expand=1

Here is a potential es.json.ts file that demonstrates the design:

import type { RequestHandler } from '@sveltejs/kit';
import type { Locals } from '$lib/types';

const wait = ms => new Promise(resolve => setTimeout(resolve, ms));

// GET /es.json
export const get: RequestHandler<Locals> = async (request) => {
    // Handle setup here..
    async function* es() {
        try {
            while (true) {
                yield `event: time\ndata: ${(new Date()).toISOString()}\n\n`;
                await wait(1000);
            }
        } finally {
            // Handle cleanup here..
        }
    }
    return {
        headers: {
            'Cache-Control': 'no-cache',
            'Connection': 'keep-alive'
        },
        body: es
    };
};

This can be called like so via es.svelte:

<script>
  import { onMount, onDestroy } from 'svelte';
  import { browser } from '$app/env';
  let timestamp = 'xxx';
  let sse = null;

  onMount(() => {
    if (!sse) {
      sse = new EventSource('/es.json');

      sse.addEventListener('time', function(e) {
        timestamp = e.data;
      });
    }
  });

  onDestroy(() => {
    if (sse) {
      sse.close();
      sse = null;
    }
  });
</script>

<svelte:head>
  <title>EventSource</title>
</svelte:head>

<div class="content">
  <h1>EventSource Example</h1>

  <p>{timestamp}</p>
</div>

<style>
  .content {
    width: 100%;
    max-width: var(--column-width);
    margin: var(--column-margin-top) auto 0 auto;
  }
</style>

This can be dropped in place in the src/routes/ directory via npm init svelte@next my-app

@babichjacob
Copy link
Member

Heavily related to #1563. Do you think we should close this and talk about it there since it's another side of the same coin (from my inexperienced perspective)?

@ignatiusmb
Copy link
Member

Closing in favor of #1563 and due to inactivity.

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

3 participants