Replies: 10 comments 20 replies
-
Maybe I am missing something here but how would the websocket API fit together with serverless targets like cloudflare workers or lambda function deployments? What happens when the remix server sleeps between requests, how would that fit together with websockets that always have to listen for messages? |
Beta Was this translation helpful? Give feedback.
-
From Ryan's comment ryanflorence — hoy a las 11:07
we'll have a table of "features supported by each adapter"
and if you try to use one with a platform that's not supported we'll throw So yeah, it's something you are going to be able to use based on the adaptar you are using, if you use Express for example you can use it, Vercel or CF will not be able to use it. Another option is to see if there are ways, maybe in the future, to enable it, maybe CF release a WebSocket feature you can use when deploying there and Remix can use that internally |
Beta Was this translation helpful? Give feedback.
-
CF does have websockets support via Durable Objects, so it's theoretically possible that the adapter could make them work that way. |
Beta Was this translation helpful? Give feedback.
-
That makes sense! The only reason my codebase is kind of complicated right now is because of a few ressource endpoints and the websocket server in my express app. If I could move that code into /app, I could get rid of my shared/ folder and manage everything in /app. Would love that! |
Beta Was this translation helpful? Give feedback.
-
Another option for serverless will be to add some logic to the client that will then ask to refetch data from the action. Maybe something on top of usefeatchers. It means that instead of using sockets to pass data it'll we be used only to tell the component to refetch. This also can integrate with long polling easily |
Beta Was this translation helpful? Give feedback.
-
This is the exact approach that SWR (stale-while-revalidate) takes and it powers Vercel's dashboard screen. It's not a bad approach considering the Javascript ecosystem is so tied into edge computing at this point. |
Beta Was this translation helpful? Give feedback.
-
Having real time data fetching/updates tied to the loaders is needed. |
Beta Was this translation helpful? Give feedback.
-
Is it best practice to have your primary web application directly host the websocket endpoint, or should a message bus oriented back-end be handling traffic like that? Do we still need to worry about long-poll now that all the clients support websocket directly? |
Beta Was this translation helpful? Give feedback.
-
I've get that to work locally, but when I deploy at vercel it just does not connect to ws client via page |
Beta Was this translation helpful? Give feedback.
-
Hi! A nice proposal! Will share my feedback below.
I find this to be insufficient. True, in WebSocket connections you are mostly interested in the transferred data but there's much more to do there. For once, you can close the client (gracefully or with an error), observe the client's URL, Proposal: Instead of accepting export const socket = ({ client }) => {
client.addEventListener('message', (event) => {})
}) As a side effect, this makes the user learn more about the WHATWG WebSocket API by handling
I fail to see a practical reason to bind a component with a WebSocket server on a route. Any route should be able to connect to your WebSocket server present on a particular route. The The API is proposed on the assumption that the component's life-cycle and the WebSocket server's life-cycle are connected and dependent. I think that's not the case. Proposal: Allow any client to connect to a WebSocket server established at a particular route. Allow any WebSocket clients to be used in a Remix app, don't lock it under a built-in
Data transferred over the WebSocket connection cannot be narrowed like that on a type-level. It's always a union of Proposal: Instead, consider adopting an type IncomingData =
| { type: 'hello' }
| { type: 'goodbye' }
type OutgoingData =
| { type: 'server/foo' }
Returning a "Protocol not supported" error response would be nice.
What is a "compatible server"? Are we talking about the deployment targets, like Vercel, Cloudflare, etc? It would be great if Remix didn't bake that support map in itself and instead relied on the deployment target to determine that for the user. It would be great to keep the set of all connected WebSocket clients in the argument to the export const socket = ({ client, clients }) => {
client // currently connected client
clients // Set<Client>, all clients connected.
}) Also, consider It would be natural to let the user handle the Upgrade request for the handshake phase of the WebSocket connection: // app/routes/api/ws.ts
export const loader = ({ request }) => {
return new Response(null, {
status: 101,
headers: {
Upgrade: 'websocket',
Connection: 'upgrade'
}
})
} Perhaps this can even be used as a basic authorization layer to see which clients are even allowed to connect.
Questions
|
Beta Was this translation helpful? Give feedback.
-
Proposal
Add built-in support for WebSockets to Remix.
Background
WebSockets are the most popular way to build real-time apps, and while SSE exists and Remix supports it out of the box, it's not so common and it's limited to one-way communication from server to client, which sometimes is desired and sometimes is not.
Use Case
API/Examples
Remix could allow a
socket
import which let you mark a route as subscribable:This
socket
function will receive any data sent from the client or broadcasted from another part of the app.To send data from the client you could use the
useSocket
hook, this will connect to the WebSocket channel associated to the route:Now you can access this from your
socket
function:Once a component unmounts the subscription should be closed.
Types
The
SocketArgs
could accept a generic to define what type of data it expects to receive, and thedata
property could be typed based on that.Broadcast from action
The
data
could also be broadcasted from anaction
function:This will allow developers to keep using
action
for mutations, and then broadcast this to every user subscribed to the channel.Broadcast from socket
This
broadcast
function will also be available on thesocket
function, this to enable clients to broadcast data to other clients subscribed to the same channel.The
broadcast
function will accept only theSocketData
value, and will broadcast to the same channel.Subscribe to different channels
A component could specify the channel to subscribe to:
This way you can subscribe to different channels from the same component.
Broadcast to different channels
The
broadcast
function could also accept apath
to broadcast to a different channel:And the same will happen on the
action
function:In both cases,
broadcast
will allow a generic to be passed to customize the expecteddata
type, if this generic is not defined it must fallback to theSocketArgs
generic inside asocket
function.Receive data from server
The
socket
object returned byuseSocket
will also let's you subscribe to the data from the server:As a convenience Remix could provide a
useSocketData
hook to be used like this:This will basically do the following:
The return type will be
Type | null
to indicate that the data could benull
if the socket is not connected yet or haven't received any value from the server.The data will also always be the latest version, is up to the user to keep track of previous values if needed.
Open questions
Beta Was this translation helpful? Give feedback.
All reactions