Skip to content

Commit cc18673

Browse files
authored
feat: add support for WDS client.webSocketURL (#529)
1 parent 48fa80e commit cc18673

File tree

2 files changed

+122
-9
lines changed

2 files changed

+122
-9
lines changed

lib/utils/getAdditionalEntries.js

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,52 @@ function getAdditionalEntries({ devServer, options }) {
1818
let resourceQuery = {};
1919

2020
if (devServer) {
21-
const { sockHost, sockPath, sockPort, host, path, port, https, http2 } = devServer;
21+
const { client, https, http2, sockHost, sockPath, sockPort } = devServer;
22+
let { host, path, port } = devServer;
2223

23-
(sockHost || host) && (resourceQuery.sockHost = sockHost ? sockHost : host);
24-
(sockPath || path) && (resourceQuery.sockPath = sockPath ? sockPath : path);
25-
(sockPort || port) && (resourceQuery.sockPort = sockPort ? sockPort : port);
26-
resourceQuery.sockProtocol = https || http2 ? 'https' : 'http';
24+
let protocol = https || http2 ? 'https' : 'http';
25+
if (sockHost) host = sockHost;
26+
if (sockPath) path = sockPath;
27+
if (sockPort) port = sockPort;
28+
29+
if (client && client.webSocketURL != null) {
30+
let parsedUrl = client.webSocketURL;
31+
if (typeof parsedUrl === 'string') parsedUrl = new URL(parsedUrl);
32+
33+
let auth;
34+
if (parsedUrl.username) {
35+
auth = parsedUrl.username;
36+
if (parsedUrl.password) {
37+
auth += ':' + parsedUrl.password;
38+
}
39+
}
40+
41+
if (parsedUrl.hostname != null) {
42+
host = [auth != null && auth, parsedUrl.hostname].filter(Boolean).join('@');
43+
}
44+
if (parsedUrl.pathname != null) {
45+
path = parsedUrl.pathname;
46+
}
47+
if (parsedUrl.port != null) {
48+
port = String(parsedUrl.port) !== '0' ? parsedUrl.port : undefined;
49+
}
50+
if (parsedUrl.protocol != null) {
51+
protocol = parsedUrl.protocol !== 'auto' ? parsedUrl.protocol.replace(':', '') : 'ws';
52+
}
53+
}
54+
55+
if (host) resourceQuery.sockHost = host;
56+
if (path) resourceQuery.sockPath = path;
57+
if (port) resourceQuery.sockPort = port;
58+
resourceQuery.sockProtocol = protocol;
2759
}
2860

2961
if (options.overlay) {
30-
options.overlay.sockHost && (resourceQuery.sockHost = options.overlay.sockHost);
31-
options.overlay.sockPath && (resourceQuery.sockPath = options.overlay.sockPath);
32-
options.overlay.sockPort && (resourceQuery.sockPort = options.overlay.sockPort);
33-
options.overlay.sockProtocol && (resourceQuery.sockProtocol = options.overlay.sockProtocol);
62+
const { sockHost, sockPath, sockPort, sockProtocol } = options.overlay;
63+
if (sockHost) resourceQuery.sockHost = sockHost;
64+
if (sockPath) resourceQuery.sockPath = sockPath;
65+
if (sockPort) resourceQuery.sockPort = sockPort;
66+
if (sockProtocol) resourceQuery.sockProtocol = sockProtocol;
3467
}
3568

3669
// We don't need to URI encode the resourceQuery as it will be parsed by Webpack

test/unit/getAdditionalEntries.test.js

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,4 +151,84 @@ describe('getAdditionalEntries', () => {
151151
],
152152
});
153153
});
154+
155+
it('should use the devServer client.webSocketURL if it is an object', () => {
156+
expect(
157+
getAdditionalEntries({
158+
options: DEFAULT_OPTIONS,
159+
devServer: {
160+
client: {
161+
webSocketURL: {
162+
hostname: 'localhost',
163+
pathname: '/socket',
164+
password: 'password',
165+
protocol: 'ws',
166+
port: 8080,
167+
username: 'username',
168+
},
169+
},
170+
},
171+
})
172+
).toStrictEqual({
173+
prependEntries: [ReactRefreshEntry],
174+
overlayEntries: [
175+
`${ErrorOverlayEntry}?sockHost=username:password@localhost&sockPath=/socket&sockPort=8080&sockProtocol=ws`,
176+
],
177+
});
178+
});
179+
180+
it('should handle devServer client.webSocketURL magic values', () => {
181+
expect(
182+
getAdditionalEntries({
183+
options: DEFAULT_OPTIONS,
184+
devServer: {
185+
client: {
186+
webSocketURL: {
187+
hostname: '0.0.0.0',
188+
pathname: '/socket',
189+
protocol: 'auto',
190+
port: 0,
191+
},
192+
},
193+
},
194+
})
195+
).toStrictEqual({
196+
prependEntries: [ReactRefreshEntry],
197+
overlayEntries: [`${ErrorOverlayEntry}?sockHost=0.0.0.0&sockPath=/socket&sockProtocol=ws`],
198+
});
199+
});
200+
201+
it('should handle devServer client.webSocketURL missing values', () => {
202+
expect(
203+
getAdditionalEntries({
204+
options: DEFAULT_OPTIONS,
205+
devServer: {
206+
client: {
207+
webSocketURL: {},
208+
},
209+
},
210+
})
211+
).toStrictEqual({
212+
prependEntries: [ReactRefreshEntry],
213+
overlayEntries: [`${ErrorOverlayEntry}?sockProtocol=http`],
214+
});
215+
});
216+
217+
it('should use the devServer client.webSocketURL if it is a string', () => {
218+
expect(
219+
getAdditionalEntries({
220+
options: DEFAULT_OPTIONS,
221+
devServer: {
222+
client: {
223+
webSocketURL: 'ws://localhost:8080/socket',
224+
},
225+
},
226+
})
227+
).toStrictEqual({
228+
prependEntries: [ReactRefreshEntry],
229+
overlayEntries: [
230+
`${ErrorOverlayEntry}?sockHost=localhost&sockPath=/socket&sockPort=8080&sockProtocol=ws`,
231+
],
232+
});
233+
});
154234
});

0 commit comments

Comments
 (0)