#Remix Utils v4.2 - Server-Sent Events edition

1 messages · Page 1 of 1 (latest)

lavish shard
#

I just released the v4.2 of Remix Utils, this version includes a hook useEventSource and a response helper eventStream to help you use SSE in a Remix app.

I tried the hook against @lusty pewter official real-time app https://github.com/remix-run/examples/tree/main/_official-realtime-app to ensure it works.

You can read how to use them here https://github.com/sergiodxa/remix-utils/tree/main#server-sent-events

GitHub

A set of utility functions and types to use with Remix.run - GitHub - sergiodxa/remix-utils: A set of utility functions and types to use with Remix.run

serene quail
#

That's amazing!

I'm thankful that @lavish shard and @sleek wave exists in our little community.

#

Is your realtime-app fork public?

lavish shard
#

I'm going to send a PR to the examples repo

#

not sure if they want to merge it (although I could merge it myself 😜 ) but let's see

#

the code is basically the same, just import eventStream and useEventSource from remix-utils

#

btw, when I tried the Linear clone Ryan built it was 🤯

serene quail
#

Waiting on the Singles release.

versed basin
#

This is awesome!

haughty steppe
#

but its damn lit you can build realtime stuff without sockets

#

or some other abstraction like firebase/supabase

#

which i assume sue sockets under the hood anyways

native moon
#

Hi, I struggle with Server Sent Events using either @lavish shard implementation with remix-utils or Ryans Linear App which is not working locally.

The sample code from remix-utils with setInterval is working fine, but emitting messages do not trigger the event 🤔

Any idea why ? I'm using Node v19 to make the node --watch command start the server

lean tiger
#

Off top of my head check if you have a dev/null route, useRefresh uses it for refresh and it wasn't in the repo when I tried it

lavish shard
#

I probably forgot to add it when I did the change inside useRevalidator

flint sierra
#

SSE + Services Workers are perfect combination for updating in background local stores

sick scarab
#

@lavish shard my loaderData looks like this {total: number; open: number; data: ComplexObject}. How can I pass the whole loaderData into the useEventSource hook and preserve types, so I get the same data as output?

lavish shard
#

so you should do JSON.parse of your data, and type it there

sick scarab
#
  const lD = useLoaderData<LoaderData>();
  const loaderData = useEventSource("/resource/sse", { event: "event" }) ?? lD;
  const { complexObject, open, total } = JSON.parse(
    loaderData as string
  ) as LoaderData;

@lavish shard like so?

lavish shard
#

yeah

#

I would use the event source to trigger a reload instead

#

not to get the loader data

#

or if you plan to do that, I would extract it to a hook

sick scarab
#

sorry newbie, what do you mean with I would use the event source to trigger a reload?

lavish shard
#
function useRealTimeLoaderData<LoaderFunction>(url: URL | string, options: EventSourceOptions) {
  let loaderData = useLoaderData<LoaderFunction>()
  let eventData = useEventSource(url, options)
  return useMemo<SerializeFrom<LoaderFunction>>(() => {
    if (!eventData) return loaderData
    return JSON.parse(eventData)
  }, [loaderData, eventData])
}

maybe I should add it to Remix Utils 🤔

lavish shard
sick scarab
#

thank you @lavish shard i will dive in 💚

plain flicker
lean tiger
#

One thing to check is to make sure that you are running express server on node and not the remix dev - with remix server the emitter doesn't have any listeners registered so you can't emit anything 😦

plain flicker
umbral chasm
#

Oh, this requires the Express server?

sick scarab
#

no, this works in the remix server. this is how i ended up doing it:

import type { SerializeFrom } from "@remix-run/server-runtime";
import { useMemo } from "react";
import { useEventSource } from "remix-utils";

type EventSourceOptions = {
  init?: EventSourceInit;
  event?: string;
};

export function useLoaderDataWithSSE<LoaderFunction>(
  loaderData: SerializeFrom<LoaderFunction>,
  url: URL | string,
  options: EventSourceOptions
) {
  let eventData = useEventSource(url, options);
  return useMemo<SerializeFrom<LoaderFunction>>(() => {
    if (!eventData) return loaderData;
    return JSON.parse(eventData);
  }, [loaderData, eventData]);
}
plain flicker
#

sorry guys, but I have no idea if I'm doing something wrong, but I can't get it working. In action my emitter doesn't have any listeners attached, so in case 2 browser windows are open, second window doesn't get event and vice-versa. Here is my repo https://github.com/p3lo/remix-sse-events . Can anyone check what I'm doing wrong please?

GitHub

Contribute to p3lo/remix-sse-events development by creating an account on GitHub.

sinful shard
#
let emitter: EventEmitter;
declare global {
  // eslint-disable-next-line no-var
  var __emmiter: EventEmitter;
}
if (process.env.NODE_ENV === 'production') {
  emitter = new EventEmitter();
} else {
  if (!global.__emmiter) {
    global.__emmiter = new EventEmitter();
  }
  emitter = global.__emmiter;
}
export { emitter };
#

change line 3 into this

#

@warm forge explains here why you should it in this way

lusty pewter
#

we're exploring how to get rid of the mostly-useful-but-sometimes-irritating require cache clearing that we do in express/remix-serve to get rid of this weirdness

lavish shard