-
Notifications
You must be signed in to change notification settings - Fork 190
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
Support webpack-hot-middleware #23
Conversation
986e7e3
to
b267db6
Compare
Hi, I am trying to use this with a custom webpack-dev-middleware and webpack-hot-middleware server. This seems to work. But for some reason, I am getting two errors:
Although I have the babel plugin, otherwise it shouldn't have worked.
|
Also there seems to be a request on |
@swashata it wasn't ready. It was very much a WIP and I hadn't touched it for a while. It's much more stable now |
@pmmmwh good news, this now works with hot-middleware! A couple questions though in the inline comments to sort out |
4d88230
to
e59a8ad
Compare
src/runtime/createSocket.js
Outdated
} else { | ||
SocketClient = require('./SockJSClient'); | ||
// } else { | ||
// SocketClient = require('./SockJSClient'); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So the main issue that webpack-hot-middleware experiences, is that since __webpack_dev_server_client__
does not get injected, we trigger this else
statement. Which also ends up crashing by failing to connect. After the third time the Socket tries to reconnect, it returns html, which then it's internals try to call res.json()
and crash, prompting the Error screen.
So i'm not really sure what the solution is here. Nor do I really understand what the use case for this custom SocketClient is. Do people really use this? I wonder if they do, if we could require a configuration option to be passed in for this.
Would love your thoughts here, as this is the main blocker for adoption in webpack-hot-middleware
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The custom SockJS client is for backwards compatibility with WDS versions before 3.8.0. Before that, WDS will return a raw SockJS client (onClose
is expressed as onclose
, and onMessage
are expressed as onmessage
, thus breaking code below).
I guess we could fix the compatibility here by detecting the methods listed above and add the wrapper only when needed as a workaround.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pmmmwh good to know. I didn't know that. So let me explain why this wasn't working with webpack-hot-middleware with your current implementation.
In this if/else statement the else statement is always hit when using webpack-hot-middleware because it does not inject that global variable __webpack_dev_server_client__
.
When we hit that else statement, the sockjs socket is initialized and starts trying to create a connection to some endpoint. This endpoint is never valid in a webpack-hot-middleware setup. So what happens then is that it tries to connect to that endpoint a couple times (has a retry mechanism internally). Then when it finally decides it can't connect, it emits an error which triggers the ErrorOverlay. 🚫
So currently any use of this plugin in webpack-hot-middleware always results in the ErrorOverlay being displayed for a SockJS connection error.
Thus the fix is to only initialized the __webpack_dev_server_client__
if we are in a webpack-dev-server mode. This is easy when the global variable is around because we can immediately detect it and know that we should use it to listen for compile messages.
When we are in webpack-hot-middleware, we do not have this sort of mechanism. The global variable it does install is not installed immediately and makes it hard to react to. The best way to do this is just to import the package directly and use it. This would be a noop in other environments because the client wouldn't do anything. But still we guard against it.
Lastly, this leave the legacy webpack setup. I was hoping there was some heuristics at build time to know if that setup was involved, but I couldn't find anything. The best option I see is that we had a configration flag for using legacy websockets. This is the implementation I have currently taken and would like your feedback and discussion on.
The new configuration is new ReactRefreshPlugin({ useLegacyWebsockets: true })
. What do you think about this approach?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think a reasonably heuristic to test for the legacy socket is via client.onmessage
- in WDS < 3.8 it will be defined, and in WDS >= 3.8 it will be undefined (client.onMessage
will be defined, instead).
There are actually two problems here (sorry for the confusion 😭):
- Support for legacy socket implementation in WDS (which can be detected via the heuristic above)
- Support for non-inline mode WDS usage - as seen in this line, WDS do not inject the client (because the whole runtime is injected via an
iframe
). While this is non-suggested usage, I think your implementation actually solved this issue.
Nonetheless, I think both are out of scope for this PR, but since you've already added the flag, maybe rename that to useLegacyWDSSockets
to indicate that it is exclusive to WDS? Then we can get this PR merged, and I can take on the first issue in another PR 🎉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome! I'll add this right now and add it to the documentation! Give me ~30m!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done! Ready for you to review/merge. Thanks @pmmmwh !
src/runtime/createSocket.js
Outdated
} else { | ||
SocketClient = require('./SockJSClient'); | ||
// } else { | ||
// SocketClient = require('./SockJSClient'); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The custom SockJS client is for backwards compatibility with WDS versions before 3.8.0. Before that, WDS will return a raw SockJS client (onClose
is expressed as onclose
, and onMessage
are expressed as onmessage
, thus breaking code below).
I guess we could fix the compatibility here by detecting the methods listed above and add the wrapper only when needed as a workaround.
Co-Authored-By: Michael Mok <pmmmwh@gmail.com>
Co-Authored-By: Michael Mok <pmmmwh@gmail.com>
Co-Authored-By: Michael Mok <pmmmwh@gmail.com>
Awesome!! Thanks for the merge, looking forward to the release @pmmmwh ❤️ |
Released in v0.2.0 🎉 |
This is a superset to #12 which was closed because I force-pushed on my branch. Apparently that is a no-no.
High Level
So, I'm not 100% certain this is the way to go. But it does seem to work. The goal of this PR is to support webpack-hot-middleware.
Involved:
Why this change
webpack-dev-server injects a runtime that has exposes a global of
__webpack_dev_server_client__
.When running an express server with webpack-dev-middleware that global is not available, but a different one will become available. I'm not sure why it's not immediately available, but in all my tests it's exposed later (hence the setTimeout + retries).The__whmEventSourceWrapper
global is an object with the whm path as the key. It's always a single key object and it's dynamic, so just grabbing the first value gives us access to the EventSource, in which we add our listener. It seems to follow the same data spec because the messageHandler continues to work!I also commented out thesock-client
code because it does not seem properly implemented. The API for when sock-client is the resolved SocketClient causes uncaught errors.Looking for feedback! I'm by no means a webpack expert, so I could surely be off here. Just wanted to get this moving because fast refresh is going to be great! Thanks for the library 😄