socketio / socket.io

Realtime application framework (Node.JS server)
https://socket.io
MIT License
60.92k stars 10.09k forks source link

Discussion around uws dependency in socket.io 2.x #2984

Closed Flux159 closed 3 years ago

Flux159 commented 7 years ago

Hi, I was doing a check of my node_modules folder last week and came across an issue around how socket.io uses the uws package as a dependency. I noticed that uws is an optional dependency with engine.io as of socket.io 2.0+ release notes and wanted to bring up a few things I noticed about it. I’ll write down how I discovered this, but because its a large post, here’s a TLDR to start with:

The long post:

To preface, I did bring this up with the uws repo first, as shown here: https://github.com/uNetworking/uWebSockets/issues/626 and here: https://github.com/uNetworking/bindings/pull/30, however the maintainer of the repo, seems to have no intention of fixing or even having a discussion around the issue.

Socket.io 2.x uses uws as an “optional” dependency. When doing some research into why my node_modules folder was ballooning in size, I noticed that uws was the 3rd largest package installed.

> du -sm node_modules/* | sort -rn | head -n 20
29  node_modules/monaco-editor
24  node_modules/nyc
11  node_modules/uws
…

Those sizes are in MB. (Before anyone comments on monaco-editor or nyc, I did make github issues/comments for those projects as well).

Checking the dependency tree using npm ls, I found that Socket.io was using uws as a dependency (technically an “optional” dependency, but will cover why its not necessarily optional below).

> npm ls uws
└─┬ socket.io@2.0.3
  └─┬ engine.io@3.1.0
    └── uws@0.14.5 

Wanting to see why uws was producing such a large npm package, I checked its directory:

> ls -l node_modules/uws/
…
-rwxr-xr-x   1 username  staff   377568 Apr 26 15:36 uws_darwin_46.node
-rwxr-xr-x   1 username  staff   377568 Apr 26 15:36 uws_darwin_47.node
-rwxr-xr-x   1 username  staff   377560 Apr 26 15:37 uws_darwin_48.node
-rwxr-xr-x   1 username  staff   377616 Apr 26 15:37 uws_darwin_51.node
-rwxr-xr-x   1 username  staff   377616 Jun 12 17:13 uws_darwin_57.node
-rwxr-xr-x   1 username  staff  1563976 Apr 26 15:11 uws_linux_46.node
-rwxr-xr-x   1 username  staff  1563976 Apr 26 15:11 uws_linux_47.node
-rwxr-xr-x   1 username  staff  1563976 Apr 26 15:11 uws_linux_48.node
-rwxr-xr-x   1 username  staff  1563976 Apr 26 15:12 uws_linux_51.node
-rwx------   1 username  staff   641024 Apr 26 15:17 uws_win32_48.node
-rwx------   1 username  staff   641536 Apr 26 15:18 uws_win32_51.node

Above, uws is packaging linux, windows, and other Mac OS X prebuilt binaries into its npm package. uws_darwin_57.node is the package that was built on my own system (using Node.js 8.x).

A couple of issues here: First, uws is packaging unnecessary binaries into its npm package - there’s no reason to have multiple platforms (“process.platform” in node) and multiple module versions (“process.versions.modules” in node) of binaries installed for one machine. This is causing the uws folder to be around 9MB larger than it needs to be. This really shouldn’t be an issue since there are well known solutions to the problem of having prebuilt binaries with npm - specifically use Github releases, AWS S3, or any other storage solution to upload binaries to, then download the appropriate binary at install time. I mentioned this to uws’s maintainer here: https://github.com/uNetworking/uWebSockets/issues/626

Since uws’s maintainer had no intention of fixing the unnecessary binary issue, I decided to make some builds using Travis CI and Appveyor using a fork of the uWebSockets repo. My fork adds an .appveyor.yml and travis.yml along with changing the install script to download from GitHub releases (and auto publishes to NPM on successful build): https://github.com/Flux159/uWebSockets https://www.npmjs.com/package/uws-light https://travis-ci.org/Flux159/uWebSockets/builds https://ci.appveyor.com/project/Flux159/uwebsockets/history Note that I do intend for anyone else to use those builds at the moment - the install script hasn’t been fully tested on all platforms (only OS X) and it was made in a very quick way.

This is where I found two other issues with uws’s npm package - the binaries that Travis CI was building for linux were significantly smaller than those in uws version 0.14.5 (1MB vs 1.5MB). I asked about this in issue 626 and received no response.

The last issue I found was with uws’s package.json install script. It was using this command:

node-gyp rebuild > build_log.txt 2>&1 || exit 0

That command will never fail since it is redirecting stderr to stdout and always exiting 0. This means that uws will still be installed “successfully” with all the prebuilt binaries even if node-gyp fails. There’s a partially reasonable reason for this if you’re trying to install uws directly from npm, but when installing engine.io this means that uws will always be installed regardless of whether its being used or not.

Again, I tried to submit a pull request to uws’s maintainer about a fix for the original issue here: https://github.com/uNetworking/bindings/pull/30 yet the pull request was rejected without (in my opinion) sufficient reasoning.

I wanted to open this issue to discuss moving engine.io’s dependency on uws to a different npm package / build due to the issues above (note I don't mean moving off of the C++ based uWebSockets, I mean moving to a different npm build of uws). Whether this is a package maintained by socket.io or someone else, that could be discussed as well (I’m purposely not recommending using my npm package / build in fairness and since I haven’t done thorough testing on it).

Ping @darrachequesne

leobudima commented 7 years ago

Fully agree with your sentiments about it being an "issue" that uws is packaging builds into their npm package (we shouldn't adopt the attitude that 9 MB is irrelevant) and compliments on thoroughly researching and covering every aspect of it.

While I think that reporting an issue here can hopefully serve to bring additional attention to the problem and potentially signal the interest of others to uws maintainer, I also do think that socket.io developers / maintainers are better utilized to fix issues directly related to the library...

brenc commented 7 years ago

I had similar problems upgrading to 2.x on Debian Wheezy (still supported until May 2018) and put in a ticket here. The install completed successfully even though uws failed to build. Somehow I noticed that ws was still being used and dug around until I found the uws build logs and saw that it failed to compile.

If engine.io can't import uws, it silently switches to ws with absolutely no indication it has done so (which is not good for a variety of reasons!). I would never have known this had I not figured it out somehow.

The uws maintainer knows uws won't compile on older LTS distros and said "I expect the user to run pretty up-to-date systems (not debian)." I managed to upgrade my systems to the next version of Debian on which uws DOES compile (with warnings), but I am still not comfortable upgrading to 2.x because of the these issues.

ws is completely sufficient for my uses (and I believe for the vast majority of use cases). Beyond this, based on the uws maintainer's comments on Debian and his comments and behaviors noted here and elsewhere, I am simply not comfortable using uws in any of my projects at all.

At the very least, I would like to see both uws and ws made completely optional and left up to the user to choose.

leoj3n commented 7 years ago

This is taking forever to run on Glitch.com:

> uws@0.14.5 install /app/node_modules/uws
7:14 AM
> node-gyp rebuild > build_log.txt 2>&1 || exit 0
7:14 AM

So, if what @brenc is talking about were made an option, then I would be able to disable full web sockets, and default to the fallback instead, which might make the install go way faster? I'm almost out of space on the hypervisor container as well (Glitch provides 125MB per instance), and although I haven't checked yet, I think it must be the compile from this very long running command.

brenc commented 7 years ago

@leoj3n can you revert to 1.7.4? I personally will not upgrade until this is all sorted out. 1.7.4 works fine for me.

ghost commented 6 years ago

@Flux159 The reason I "don't listen to criticism" is because your criticism is in direct opposition to other users criticism. You see anything popular will always result in some pleased users and some displeased users. You simply cannot cater for everyone. If 10mb of disk space is such a major deal for you, then maybe ws is the better choice for you. If you look at the very early issue reports of uws you will see this very topic being discussed in many different ways. Some users are opposed to binaries altogether, some users need node-gyp builds, some users just want things to work. I try and be open to all criticism and I try and balance it so that 90% are pelased and 10% are displeased. If you look at the download stats of uws and look at how the industry is using it (there are some very high-profile users of it), they seem to be perfectly pleased with it overall. If you really care that much about 10mb of disk space then you could really just go into the uws folder and delete those binaries you won't need. I have reported this issue to NPM (about being able to upload per-platform binaries) but they refuse to listen. Again, I cannot change something as fundamental as the installation of something this well-used just because 3 users feel 10mb of disk space is too heavy. uws makes heavy use of C++ templates and prioritizes performance over disk space. This is why, for instance, I build the Linux binaries statically against libc++ - this has drawbacks such as increased disk space usage but also makes the lib work out of the box on virtually any Linux box. Pros and cons.

STRML commented 6 years ago

The https://github.com/uNetworking/bindings/ repository has been completely removed, and now there is no place to track development of the NodeJS bindings for uws. @alexhultman, was this intentional?

ghost commented 6 years ago

si

STRML commented 6 years ago

Okay. Something up / something I can help with? Since issues are not active, it's difficult to tell if you are discontinuing it, moving it, etc - docs now have broken links and pages are not resolvable.

ghost commented 6 years ago

Only nodejs binding is discontinued, C++ core is not. I have a chat if you want more info

STRML commented 6 years ago

Yeah, please do. Contact info is on my profile. For the benefit of users here I'd like to update this issue with future plans after we have that discussion.

telemakhos commented 6 years ago

@alexhultman, now that @STRML and BitMEX are sponsoring the project, is the repo with the node bindings going to come back anytime soon? or should we use any of the existing forks for the time being?

STRML commented 6 years ago

See https://github.com/uNetworking/uWebSockets-bindings

darrachequesne commented 3 years ago

For future readers, ws was reverted as the default WebSocket server implementation in socket.io@2.1.0

There is a fork of uws, called eiows, for those interested.

Documentation: https://socket.io/docs/v3/server-installation/#Other-WebSocket-server-implementations