Why I Avoid Working With WebSockets in NextJS and tRPC

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
listen man I think working with web sockets and trpc the way it's meant to be used according to their documentation is kind of s and the reason I say that is because the way it's meant to be in their documentation you neither get the benefit of working directly with the server nor do you really get the benefit of type safety and I'm gonna get into the details in this video but it just doesn't really make sense to me man I'll be the first one to say that I've got massive respect for everybody working on trpc because I think they've done a great job regarding the query and the mutation and the type safety they've implemented in that regard just the subscription I think needs some work at least the way it's meant to be used in their documentation now let's get into the details of why working with trpc and web sockets inside of nexjs just doesn't go well together okay so here we are in xjs and trpc with a websockets connection already set up and the reason we are in a project that already has the websocket set up is because I don't think it makes too much sense going through the whole setup process because it's a pain honestly it's not cool you get a bunch of errors and you always have to figure out why you get this error like why is this not defined why is that not defined because in the documentation it's not clear at all so I can show you the documentation trpc V10 and we when you go down to right here subscription websockets there is like an instruction on how to set up the web sockets but it's kind of incomplete so you know this is not the best approach for example this one right here this doesn't really make sense you'll get an arrow that says like web sockets is not defined because this will be run on the server and the server doesn't know a websockets so you get a bunch of errors and the setup process inside of trpc and Nexus it's just not worth it so that's why we are in a project that already has websockets set up I went through the entire process so let me show you how the data flow works and then why this is not the ideal setup that you would probably want to use in a production app so this integration consists of a bunch of files but most importantly two parts we have the front end and then the back end so this is our websockets server that means we are hosting it on Port 3001 we need to set up a bunch of boilerplate that's not really important we just need that for the signal termination essentially we have a websockets connection once the connection is established from the client side we get a plus plus connection and once the connection is closed we get a minus minus connection so let me show you that when we got uh we can close the previous instance when we go to localhost 3000 we can look into the let me close the second tab actually we can go into right here and we see the connection was established so we have connection one and two which is both this client by the way and if I close this connection right here you can see the server logs out that the connection has been closed okay so where's the problem in establishing um the server right here and then having you know a router to actually interact with the websockets well the problem is that you can't really get data from the server as if you were having like an Express and socket.io integration which I much prefer over this approach but then you don't get the type safety type safety is important but I think this approach is just not the way to go so in order to subscribe to the websockets like to make the connection we have to call a function from the front end which is essentially just a trpc DOT and then the router so the Ws router and WS subscription that you can see right here and then use subscription because this is a subscription we always have to use a subscription when we're working with websockets now from trpc this is required to return an observable and then listen to whatever is emitted from the mutations so from the client when pressing a button we trigger a mutation the mutation um triggers this right here so whenever we click the button on the front end that is this button right here mutate then this function will be run on the back end so we are in the server side here and we are essentially just emitting something that is called test now we can Define this by ourselves whatever we want to emit important is that the server is listening so whenever test is emitted from right here the test function will be run so that's that would be this function right here and the emit dot next just means we are propagating whatever data is back here to the client and that must be of this type so if I change the type then we will get an error right here um so in this case we can only send strings back to the client now if I were to save that though we get uh you know a bunch of Errors errors is pretty much all you get when trying this options this undefined uh and whatever I think that is because we actually need to have an on data here that really doesn't need to do anything um but I think that is yeah that that is the reason for the error it's very in transparent and sometimes if you Google you won't find much uh documentation sadly um so whenever we click this button right now let me open the console and now when we click mutate it says mutated successfully so what happened is we invoke the mutation it's the test mutation.use mutation so this function right here it emitted the test the test event is listened to on the Ws server which is this one then the test function is run so this function is run and that says emit dot next so send back to the client this message and this message mutated successfully is then received by the on data as the data property you can see it's the string so it's whatever type we declared right here is being returned and then we're logging that data out which is the string of mutated successfully now this approach has limitations though so let's say we want to create a game and this is exactly the use case I wanted to try out with this approach and it didn't work um let's let's create a game and whenever a user connects the user also needs to know what other clients are connected to the game obviously um now with this approach you can't really do that because how do you keep track of who is connected and who is not well you do that on the server on the WSS server so the a connection is established and then a web sockets know okay we have this user so if you take a look right now there is like one open connection which is this window right here if I were to connect with another one it keeps track on the uh server so we have four connections and because each client right here is establishing two connections um that just means we have two clients connected pretty much um now every client is saved on the server and when we disconnect that is removed from the server we've already taken a look at that now let's say on the front end we need to know which clients are connected though so far in a game that would mean how many actual players should be shown on the screen or how many um if you want to have a shared Mouse window like where each Mouse of every connected client is visible then you need to know which clients are connected and where are their Mouse cursors with this approach you can't really do it though because where would you keep track of the clients right you don't have access to the actual server back here so you can't know which connections are established and one approach would be to keep track of like the clients right here as a like a map for example and then whenever a connection is established then you could add the clients or clients Dot it would be sets and we're gonna set for example like yeah that's the question what would be set in this instance we would have the actual socket connection but in this one we would have to create a random ID and then we could save like you know what would we really save as the client I don't I don't really know it's not very intuitive and keeping track of clients this way is not really good nonetheless because in other Integrations like socket.io for example that would be completely redundant and also I've literally tried this approach and it works very unreliably so this wouldn't really be the way to go and that is pretty much crucial information you need from the server that you don't get when you're using this approach and as far as I know there is no real way to do this um and even if you search for like documentation online there is no knowledge that you can you know get back to the only thing is pretty much what is explained on this website right here and then there are two projects that you can have a look at this one is like a very Bare Bones so there's not a lot of knowledge to be taken from that and then there is a you know full stack example that uh you know it is good but it doesn't really show like what we need to do like interacting with the server so while you do get type safety in this approach I don't think it's very viable now you might say okay if you need to interact with a server and get the connected clients why don't you integrate socket.io which does all of that for you it's basically a websockets kind of abstraction that is you know more graceful in handling reconnects for example I need to do that on the server and then connect the server on the front end for example with cons socket is equal to either new web socket you could do that and then have like a domain right here that is actually one method you could connect to the server but it still wouldn't really be the best approach in my opinion um and we can take a look at what happens when we integrate websocket.io and this back end right here because technically that should solve all our problems right we get the type safety from the mutations and trpc and then we can also interact with the server directly on the front end and get how many clients are connected and how many clients uh you know disconnect and connect and just basically keep an accurate state of who's connected and who's not but let me paste in some socket.io code right here um I've already installed the dependencies so that's why we are not getting an error and in socket.io we can for example delete all of this and whenever a client connects then we're just gonna emit a message to every connected client of type connection now actually let's let's just call it user connect and then as an argument we're gonna pass we don't need an argument anyways so whenever a user connects that is going to get sent to All instances and now in the front end we can say current socket is equal to IO and IO is going to come from the socket.io client side and that is going to be localhost 3001 because that's what we said right here and now that technically should solve all our problems right so we can have a use effect right here we don't need most of the stuff um but let's just say whenever um this event is triggered so user connected this needs to match what is emitted right here is there connected then we're gonna log something out to the console which is going to be a user connected and with this approach we would actually uh be able to see how many clients and who is connected to this current uh WS server um and send that back to the front end so let's take a look at what happens and you'll see we can go back in here and we don't get any error but as you can see in here Firefox can't establish a connection to the server at WS localhost 3001 now why is that issue happening when we go into the utils crpc we can see whenever we are on the server then the trpc will initialize the links as the HTTP patch link because the server doesn't know what websockets are and whenever we're on the client we are initializing the websocket client because now we can actually work with the websockets API and I think the error message here is a bit misleading so whenever we open that in Chrome you can see the actual source of the error so here it just says underscore app.js but to make it clear to you I want to show you where the error happens so right here it says WS link.mjs which is right here so we can't establish a websockets connection in doing this and you know one approach might be to have the Ws link right here and then well we can just we can just copy this down here instead of this so we have the link links as an array that contains the Ws link save that and we can reload the page and you see websocket is not defined because now we are trying to initialize the web socket on the server which doesn't make sense but if we try to for example return the batch link instead of the Ws link we can do that and that wouldn't throw an error but now the issue we have that our web sockets are not really connected you see here user connected so that works but that is just because socket.io in the back end and the front end are communicating directly but if we want to use the invitation form earlier you remember it should log out muted successfully so that's what should happen whenever we click the button because that's what happened earlier but if we click mutate and I'm clicking right now nothing thing happens because we are not connected to the websocket server that is this one right here so every emit that we do and we can log this out this event is being emitted so emit the test the mutation is working and if we go back to the server then you can see either met a test so if I click this a bunch of times you can see the the mutation is working so the emit is actually being emitted but because we are not connected to the websocket server in trpc nobody is there to listen to the emit happening and therefore no data is being sent back to the client and this ondata is never running so that means I don't think there is a good approach in working with trpc and getting the type safety and also using your actual websocket server now I might be wrong and I hope I am because you know there is no real good documentation available online but as of now I think that is one big issue that trpc has in next shares and the only approach that I prefer is actually not having type safety and just working with socket.io and the Ws server directly without any middleman like trpc with mutations and subscriptions because they just make things more unintuitive and don't work and that was pretty much all I wanted to show you in this video thank you for watching and I'm looking forward to seeing you in the next one have a good one and bye
Info
Channel: Josh tried coding
Views: 17,640
Rating: undefined out of 5
Keywords: trpc, typescript, nextjs, websockets, nextjs websockets, nextjs typescript, beginner, project, tutorial, nextjs beginner
Id: e5Cye4pIFeA
Channel Id: undefined
Length: 16min 21sec (981 seconds)
Published: Mon Oct 31 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.