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

onEvent not working + small issue with package.json #1

Open
milansimek opened this issue May 17, 2023 · 14 comments
Open

onEvent not working + small issue with package.json #1

milansimek opened this issue May 17, 2023 · 14 comments

Comments

@milansimek
Copy link

First of all thanks for this package, saved me some time 😄

It didn't work for me out of the box. Had to make some small adjustments to make it work.

Would you like me to fork the repo and create a pull request?

I just needed to make 2 small changes so I can describe them here instead if you prefer.

@ubermanu
Copy link
Owner

ubermanu commented May 19, 2023

Hey Milan,

of course! feel free to fork it

but i'm not sure it will work outside of your dev env
not so long ago I've read that this will run only with the vite dev server (since it's a vite plugin)

so I need to dive deeper into the node adapter to see what's possible

@milansimek
Copy link
Author

Alright will do that!

I was actually planning to just use the vite dev environment and use Nginx as a reverse proxy in front of it. It's my first SvelteKit project so I'm not that familiar yet with best practices.

Is there any reason to not use the npm run build and npm run preview -- --host commands in production? Seems to me it's just running a nodeJS server so I'm not sure if it's any different from a "real" nodeJS server behind the scenes?

Thanks!

@milansimek
Copy link
Author

@ubermanu Oh lol I see now those commands don't work indeed 😂

I'll check if I can make it work with the node adapter and will let you know

@ubermanu
Copy link
Owner

you should always build before publishing in production
for example, if you have some prerendered pages, those HTML pages are generated at build time

for the websocket implementation, you can check out this thread sveltejs/kit#1491 (comment) (it's still an ongoing thing 🥹)

and also https://www.npmjs.com/package/@carlosv2/adapter-node-ws might do already the work I guess but I never actually tried it

@milansimek
Copy link
Author

you should always build before publishing in production

Yes of course :) Just didn't test the websockets after building so didn't realize it wouldn't work.

Thanks for sharing the link to the discussion, will check it out.

I'm currently writing a tiny app to manage a print queue in real time. It's essentially a single page with the queue items and some API endpoints. Will probably get away with not running build for now.

On second thought I might decide to run a separate node process with socket.io. Seems like a more straightforward solution for the time being..

@ubermanu
Copy link
Owner

yea that's pretty much what a lot of people end up doing afaik 😅

@milansimek
Copy link
Author

milansimek commented May 20, 2023

@ubermanu I managed to get it working :D Used the following steps:

  • Created a singleton for the socketio server
  • When initialized it creates a websocket server on port 3001
  • The singleton is imported in hooks.server.js making it start at the first request.
  • Built the app using adapter-node
  • Created new entrypoint js file which uses express on port 3000 (using the "custom server" example here)
  • Proxied route /socket.io to port 3001 using http-proxy-middleware for express

So for the client everything is running on the same port, while behind the scenes socket.io runs on port 3001.

I also added a proxy entry to vite config, so it works with vite dev also :)

@ubermanu
Copy link
Owner

Nice! I'll try your setup next week 😁

@milansimek
Copy link
Author

I've now created a custom adapter which adds a proxy to the polka server of the node adapter provided by sveltekit. It modifies the index.js entrypoint script generated by the node adapter after it's created.

It first executes the node-adapter and then runs some find/replace logic to add the proxy.

gist: https://gist.github.com/milansimek/4e51825ca30c7cfe019f68bc3922c8f0

Since it modifies the index.js generated by the default adapter, it includes all functionality that's provided by it. And it works completely automated so no need to manually create a different entrypoint 😁

@ubermanu
Copy link
Owner

that's nice!

I've started to implement your solution, but with a ws server integrated into the polka httpServer instance directly and i got it working in dev+build (preview is on the way)

I'v also removed all the client side stuff for the moment, exposing a more sveltekit api, which is a readable store without any interaction
but since there is only one connection to the server, it might be a nice to have feature to expose the socket already configured?

also i replaced all the socket-io server stuff with the ws package (which is closer to the native WebSocket implementation)

@milansimek
Copy link
Author

milansimek commented May 22, 2023

Nicee! 👍

but since there is only one connection to the server, it might be a nice to have feature to expose the socket already configured?

Yes, that's why I used a singleton for that. I got rid of the hooks.websocket.js completely and used this instead:

https://gist.github.com/milansimek/f801793fe102c8b4c61ebf1def97ae84

This implementation allows you to:

  • On socket io server events: Access/manipulate the running svelte app including stores
    (it's not isolated from the main application like is the case with hooks.websocket.js)
  • Access the initialized socket io server anywhere in the code (by including the ioserver singleton)
  • Add new event listeners to the server at arbitrary points in the app

@milansimek
Copy link
Author

milansimek commented May 22, 2023

Forgot to mention:
The biggest advantage of the implementation I described above is that you can emit server side websocket events from server-only endpoints.

For example I have an API endpoint which should create a new row in the print queue and send an event with the row to all connected clients.

To do so I can simply use this:
https://gist.github.com/milansimek/00e7045908f7ebe179acd38fe6c5e3e3

@ubermanu
Copy link
Owner

ah okok i see now, makes sense

it feels a bit weird to me to instantiate a whole service on request processing but the built version works nicely 👏
on the other hand, I couldn't figure out why the dev version cannot run, I do have it proxied in my vite config, but maybe it just dies before i can connect to it

also, i'm not sure it's possible to have some kind of universal implementation for this tbh
the longer i wrap my head around it, i feel like it cannot be achieved in a nice way just using a vite plugin + adapter

we could implement that directly into sveltekit, but it feels weird to have this feature exclusively built for the node adapter

@milansimek
Copy link
Author

Did you try using socketio or using ws?

Vite uses websockets for HMR, this might be related. Socket.io uses the reserved endpoint /socket.io/, maybe this has the side effect that it doesn't conflict with the HMR web socket functionality. (just an educated guess)

Are you getting any errors in dev tools or server console?

My vite.config.js looks like this:

export default defineConfig({
	plugins: [
        sveltekit() 
    ],
    server: {
        proxy: {
            '/socket.io/': 'http://localhost:3001'
        }
    }
});

For the client side library I'm using a modified version of your original code:

https://gist.github.com/milansimek/188d5c70aecf2b54934d8a527307fd2f

(if I remember correctly the main difference is in the onAny callback)

Another thing: During HMR in some cases the socket server singleton gets reloaded, which causes a fatal error. To solve this I added an on error callback to the ioserver singleton:

this.httpServer.listen(3001).on('error', (e) => { });

I have no idea why, but this works lol.

it feels a bit weird to me to instantiate a whole service on request processing

I agree 100%. There should be a more elegant way to do make the socket server accessible throughout the application.

I'm wondering why the hooks.websocket.js is isolated from the other code. When instantiating a singleton or store there, they are not "connected" to the main application.

Probably checking how hooks.server.js is loaded will give some ideas.

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

2 participants