refactor(client): reuse webpack-dev-middleware's hot client - #5750
Draft
alexander-akait wants to merge 1 commit into
Draft
alexander-akait wants to merge 1 commit into
alexander-akait wants to merge 1 commit into
Conversation
First step of moving the hot clients into webpack-dev-middleware: this
package's `WebSocketClient` is a strict subset of the one that package now
ships, and worse in three ways. It has no `close()` at all, despite
declaring `@implements {CommunicationClient}`, which the interface requires.
It has no guard against an event the socket had already queued reporting
after the caller closed, so a close could schedule a reconnection nobody
asked for. And it hands the url to `new WebSocket` unresolved, which throws
on browsers before Chrome 125 / Firefox 124 / Safari 17.3 for a relative or
`http(s):` url — this package always builds an absolute `ws:` url, so that
one never bit here, but it is a trap for anyone reusing the class.
Re-exported rather than deleted: `client.webSocketTransport` resolves to
this path, so anything pointing at it keeps working.
`import/no-unresolved` is switched off for the file, following the exemption
already in place for `@changesets/get-github-info`: the import resolver
cannot follow an `exports` subpath. TypeScript does resolve it, so
`lint:types-client` still covers the import.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UjuMAuk9o6UazjHzcAQCTA
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Draft, and it has to stay one until webpack-dev-middleware is released. CI is red here for a reason outside the diff — see Why CI cannot pass yet below. Opened now so the plan and the findings are reviewable before the large part lands.
Summary
First step of moving the hot clients into webpack-dev-middleware, so this package stops carrying its own. This commit takes the WebSocket transport class.
This package's
WebSocketClientis a strict subset of the one dev-middleware now ships, and worse in three ways:close()at all, despite declaring@implements {CommunicationClient}— the interface requires it;new WebSocketunresolved, which throws on browsers before Chrome 125 / Firefox 124 / Safari 17.3 for a relative orhttp(s):url. This package always builds an absolutews:url so it never bit here, but it is a trap for anyone reusing the class.Re-exported rather than deleted, because
client.webSocketTransportresolves to this path.Why CI cannot pass yet
webpack-dev-middleware@8.3.0on npm exports only./client,./client/indicatorand./client/overlay. There is no./client/ws— that export landed in webpack/webpack-dev-middleware#2421, which is merged tomainbut unreleased. So the specifier this commit imports does not resolve against the published dependency at all: it is not merely a types problem, webpack cannot resolve it either.Two dev-middleware changes therefore gate this PR:
./client/ws;./client/*exports could be imported by a TypeScript consumer at all, because no declarations were emitted for them and the client is ESM inside a CommonJS package.lint:types-clienthere only passes with that in.Once dev-middleware releases, this needs a dependency bump and nothing else.
Tested against dev-middleware's
main, not a guess: built and packed frommain, installed here, and the suites run against it. Baselines taken first, so the comparison means something:test/client/index.test.jstest/e2e/web-socket-server-url.test.jstest/e2e/overlay.test.jsThe failures are identical with and without the change and reproduce on a clean
mainin that container — the 5 are("ws")cases needing local-ip/IPv4 host resolution, and the overlay suite fails there for environmental reasons. Not introduced here, and not claimed as passing.What the rest of the move needs, and what blocks it
Worth stating before the big commit, because the plan said "delete
client-src/and re-export dev-middleware's client" and that turns out to understate it. The two packages do not speak the same protocol. This package sends{ type, data }withok/still-ok/invalid/hash/static-changed/progress-update; dev-middleware sends{ action }withbuilding/progress/built/sync. Swapping the client means adopting its protocol on the server side too.Three things make that tractable and one blocks it:
hot,liveReload,progress,reconnect,overlayandloggingper client on connect — and already puts all of them in the client entry query. dev-middleware's client reads them from the query, including this package's spellings (webSocketURL,reconnect,live-reload). So the push can go.static-changedhas a home: published throughhot.publishand picked up by the client'ssubscribe()hook for actions it does not recognise.hash/still-okare covered by thebuilt/syncpayloads, which carry the hash, errors and warnings.Host/Originon connection and sendserrorthen closes. dev-middleware's WebSocket server has no hook for that, so delegating the server would silently drop an origin check — security-relevant, not cosmetic. It needs a small addition there first.preventReloadingon warnings has no dev-middleware equivalent.What kind of change does this PR introduce?
refactor
Did you add tests for your changes?
No new tests in this commit — it swaps an implementation for a superset of itself, and the existing client and e2e suites cover it. The behaviour that is new (a working
close(), the closed guard, url resolution) is already tested in dev-middleware.Does this PR introduce a breaking change?
No.
client.webSocketTransportkeeps resolving to the same path, and the class answers the same interface — plus theclose()it was supposed to have.If relevant, what needs to be documented once your changes are merged or what have you already documented?
Nothing for this commit. The full move will want a note that the client is dev-middleware's, and the
client.overlaykeys that gains (styles,ansiColors,openEditorEndpoint,paginate).Use of AI
AI-assisted (Claude Code). Used to compare the two transports, make the swap, and verify it against a pack of dev-middleware's
mainwith baselines taken before and after; also to work out what the remaining steps need, which is where the protocol divergence and the missing origin-check hook came from.🤖 Generated with Claude Code
https://claude.ai/code/session_01UjuMAuk9o6UazjHzcAQCTA