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

feat: add client.reconnect option #3912

Merged
merged 17 commits into from Oct 9, 2021
2 changes: 2 additions & 0 deletions README.md
Expand Up @@ -93,6 +93,8 @@ Options:
--client-logging <value> Allows to specify options for client script in the browser or disable client script.
--client-progress Prints compilation progress in percentage in the browser.
--no-client-progress Does not print compilation progress in percentage in the browser.
--client-reconnect [value] Tells dev-server the number of times it should try to reconnect the client.
--no-client-reconnect Tells dev-server to not to try to connect the client.
--client-overlay Enables a full-screen overlay in the browser when there are compiler errors or warnings.
--no-client-overlay Disables a full-screen overlay in the browser when there are compiler errors or warnings.
--client-overlay-errors Enables a full-screen overlay in the browser when there are compiler errors.
Expand Down
23 changes: 23 additions & 0 deletions bin/cli-flags.js
Expand Up @@ -174,6 +174,29 @@ module.exports = {
simpleType: "boolean",
multiple: false,
},
"client-reconnect": {
configs: [
{
type: "boolean",
multiple: false,
description:
"Tells dev-server the number of times it should try to reconnect the client.",
path: "client.reconnect",
},
{
type: "number",
multiple: false,
description:
"Tells dev-server the number of times it should try to reconnect the client.",
path: "client.reconnect",
},
],
description:
"Tells dev-server the number of times it should try to reconnect the client.",
negatedDescription: "Tells dev-server to not to try to connect the client.",
simpleType: "string",
multiple: false,
},
"client-web-socket-url": {
configs: [
{
Expand Down
13 changes: 12 additions & 1 deletion client-src/index.js
Expand Up @@ -41,6 +41,10 @@ if (parsedResourceQuery.logging) {
options.logging = parsedResourceQuery.logging;
}

if (typeof parsedResourceQuery.reconnect !== "undefined") {
options.reconnect = Number(parsedResourceQuery.reconnect);
}

function setAllLogLevel(level) {
// This is needed because the HMR logger operate separately from dev server logger
webpackHotLog.setLogLevel(
Expand Down Expand Up @@ -98,6 +102,13 @@ const onSocketMessage = {

options.overlay = value;
},
reconnect(value) {
if (parsedResourceQuery.reconnect === "false") {
return;
}

options.reconnect = value;
},
progress(progress) {
options.progress = progress;
},
Expand Down Expand Up @@ -215,4 +226,4 @@ const onSocketMessage = {

const socketURL = createSocketURL(parsedResourceQuery);

socket(socketURL, onSocketMessage);
socket(socketURL, onSocketMessage, options.reconnect);
9 changes: 7 additions & 2 deletions client-src/socket.js
@@ -1,6 +1,7 @@
/* global __webpack_dev_server_client__ */

import WebSocketClient from "./clients/WebSocketClient.js";
import { log } from "./utils/log.js";

// this WebsocketClient is here as a default fallback, in case the client is not injected
/* eslint-disable camelcase */
Expand All @@ -15,13 +16,15 @@ const Client =
/* eslint-enable camelcase */

let retries = 0;
let maxRetries = 10;
let client = null;

const socket = function initSocket(url, handlers) {
const socket = function initSocket(url, handlers, reconnect) {
client = new Client(url);

client.onOpen(() => {
retries = 0;
maxRetries = reconnect;
});

client.onClose(() => {
Expand All @@ -33,14 +36,16 @@ const socket = function initSocket(url, handlers) {
client = null;

// After 10 retries stop trying, to prevent logspam.
if (retries <= 10) {
if (retries < maxRetries) {
// Exponentially increase timeout to reconnect.
// Respectfully copied from the package `got`.
// eslint-disable-next-line no-mixed-operators, no-restricted-properties
const retryInMs = 1000 * Math.pow(2, retries) + Math.random() * 100;

retries += 1;

log.info("Trying to reconnect...");

setTimeout(() => {
socket(url, handlers);
}, retryInMs);
Expand Down
16 changes: 16 additions & 0 deletions lib/Server.js
Expand Up @@ -258,6 +258,10 @@ class Server {
searchParams.set("logging", this.options.client.logging);
}

if (typeof this.options.client.reconnect !== "undefined") {
searchParams.set("reconnect", this.options.client.reconnect);
}

webSocketURL = searchParams.toString();
}

Expand Down Expand Up @@ -474,6 +478,14 @@ class Server {
};
}

if (typeof options.client.reconnect === "undefined") {
options.client.reconnect = 10;
} else if (options.client.reconnect === true) {
options.client.reconnect = Infinity;
} else if (options.client.reconnect === false) {
options.client.reconnect = 0;
}

// Respect infrastructureLogging.level
if (typeof options.client.logging === "undefined") {
options.client.logging = compilerOptions.infrastructureLogging
Expand Down Expand Up @@ -1627,6 +1639,10 @@ class Server {
this.sendMessage([client], "progress", this.options.client.progress);
}

if (this.options.client && this.options.client.reconnect) {
this.sendMessage([client], "reconnect", this.options.client.reconnect);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need handler in our client for this like for progress/etc, so developers can change value using web socket API


if (this.options.client && this.options.client.overlay) {
this.sendMessage([client], "overlay", this.options.client.overlay);
}
Expand Down
16 changes: 16 additions & 0 deletions lib/options.json
Expand Up @@ -59,6 +59,9 @@
"progress": {
"$ref": "#/definitions/ClientProgress"
},
"reconnect": {
"$ref": "#/definitions/ClientReconnect"
},
"webSocketTransport": {
"$ref": "#/definitions/ClientWebSocketTransport"
},
Expand Down Expand Up @@ -102,6 +105,19 @@
"link": "https://webpack.js.org/configuration/dev-server/#progress",
"type": "boolean"
},
"ClientReconnect": {
"description": "Tells dev-server the number of times it should try to reconnect the client.",
"link": "https://webpack.js.org/configuration/dev-server/#reconnect",
"anyOf": [
{
"type": "boolean"
},
{
"type": "number",
"minimum": 0
}
]
},
"ClientWebSocketTransport": {
"anyOf": [
{
Expand Down
30 changes: 23 additions & 7 deletions test/__snapshots__/validate-options.test.js.snap.webpack4
Expand Up @@ -83,7 +83,7 @@ exports[`options validate should throw an error on the "client" option with '{"l
exports[`options validate should throw an error on the "client" option with '{"overlay":""}' value 1`] = `
"ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
- options.client should be one of these:
false | object { logging?, overlay?, progress?, webSocketTransport?, webSocketURL? }
false | object { logging?, overlay?, progress?, reconnect?, webSocketTransport?, webSocketURL? }
-> Allows to specify options for client script in the browser or disable client script.
-> Read more at https://webpack.js.org/configuration/dev-server/#devserverclient
Details:
Expand Down Expand Up @@ -122,16 +122,32 @@ exports[`options validate should throw an error on the "client" option with '{"p
-> Read more at https://webpack.js.org/configuration/dev-server/#progress"
`;

exports[`options validate should throw an error on the "client" option with '{"reconnect":""}' value 1`] = `
"ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
- options.client should be one of these:
false | object { logging?, overlay?, progress?, reconnect?, webSocketTransport?, webSocketURL? }
-> Allows to specify options for client script in the browser or disable client script.
-> Read more at https://webpack.js.org/configuration/dev-server/#devserverclient
Details:
* options.client.reconnect should be one of these:
boolean | number (should be >= 0)
-> Tells dev-server the number of times it should try to reconnect the client.
-> Read more at https://webpack.js.org/configuration/dev-server/#reconnect
Details:
* options.client.reconnect should be a boolean.
* options.client.reconnect should be a number (should be >= 0)."
`;

exports[`options validate should throw an error on the "client" option with '{"unknownOption":true}' value 1`] = `
"ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
- options.client has an unknown property 'unknownOption'. These properties are valid:
object { logging?, overlay?, progress?, webSocketTransport?, webSocketURL? }"
object { logging?, overlay?, progress?, reconnect?, webSocketTransport?, webSocketURL? }"
`;

exports[`options validate should throw an error on the "client" option with '{"webSocketTransport":true}' value 1`] = `
"ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
- options.client should be one of these:
false | object { logging?, overlay?, progress?, webSocketTransport?, webSocketURL? }
false | object { logging?, overlay?, progress?, reconnect?, webSocketTransport?, webSocketURL? }
-> Allows to specify options for client script in the browser or disable client script.
-> Read more at https://webpack.js.org/configuration/dev-server/#devserverclient
Details:
Expand Down Expand Up @@ -171,7 +187,7 @@ exports[`options validate should throw an error on the "client" option with '{"w
exports[`options validate should throw an error on the "client" option with '{"webSocketURL":{"port":true}}' value 1`] = `
"ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
- options.client should be one of these:
false | object { logging?, overlay?, progress?, webSocketTransport?, webSocketURL? }
false | object { logging?, overlay?, progress?, reconnect?, webSocketTransport?, webSocketURL? }
-> Allows to specify options for client script in the browser or disable client script.
-> Read more at https://webpack.js.org/configuration/dev-server/#devserverclient
Details:
Expand All @@ -186,7 +202,7 @@ exports[`options validate should throw an error on the "client" option with '{"w
exports[`options validate should throw an error on the "client" option with '{"webSocketURL":{"username":123,"password":976}}' value 1`] = `
"ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
- options.client should be one of these:
false | object { logging?, overlay?, progress?, webSocketTransport?, webSocketURL? }
false | object { logging?, overlay?, progress?, reconnect?, webSocketTransport?, webSocketURL? }
-> Allows to specify options for client script in the browser or disable client script.
-> Read more at https://webpack.js.org/configuration/dev-server/#devserverclient
Details:
Expand All @@ -199,13 +215,13 @@ exports[`options validate should throw an error on the "client" option with '{"w
exports[`options validate should throw an error on the "client" option with 'whoops!' value 1`] = `
"ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
- options.client should be one of these:
false | object { logging?, overlay?, progress?, webSocketTransport?, webSocketURL? }
false | object { logging?, overlay?, progress?, reconnect?, webSocketTransport?, webSocketURL? }
-> Allows to specify options for client script in the browser or disable client script.
-> Read more at https://webpack.js.org/configuration/dev-server/#devserverclient
Details:
* options.client should be false.
* options.client should be an object:
object { logging?, overlay?, progress?, webSocketTransport?, webSocketURL? }"
object { logging?, overlay?, progress?, reconnect?, webSocketTransport?, webSocketURL? }"
`;

exports[`options validate should throw an error on the "compress" option with '' value 1`] = `
Expand Down
30 changes: 23 additions & 7 deletions test/__snapshots__/validate-options.test.js.snap.webpack5
Expand Up @@ -83,7 +83,7 @@ exports[`options validate should throw an error on the "client" option with '{"l
exports[`options validate should throw an error on the "client" option with '{"overlay":""}' value 1`] = `
"ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
- options.client should be one of these:
false | object { logging?, overlay?, progress?, webSocketTransport?, webSocketURL? }
false | object { logging?, overlay?, progress?, reconnect?, webSocketTransport?, webSocketURL? }
-> Allows to specify options for client script in the browser or disable client script.
-> Read more at https://webpack.js.org/configuration/dev-server/#devserverclient
Details:
Expand Down Expand Up @@ -122,16 +122,32 @@ exports[`options validate should throw an error on the "client" option with '{"p
-> Read more at https://webpack.js.org/configuration/dev-server/#progress"
`;

exports[`options validate should throw an error on the "client" option with '{"reconnect":""}' value 1`] = `
"ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
- options.client should be one of these:
false | object { logging?, overlay?, progress?, reconnect?, webSocketTransport?, webSocketURL? }
-> Allows to specify options for client script in the browser or disable client script.
-> Read more at https://webpack.js.org/configuration/dev-server/#devserverclient
Details:
* options.client.reconnect should be one of these:
boolean | number (should be >= 0)
-> Tells dev-server the number of times it should try to reconnect the client.
-> Read more at https://webpack.js.org/configuration/dev-server/#reconnect
Details:
* options.client.reconnect should be a boolean.
* options.client.reconnect should be a number (should be >= 0)."
`;

exports[`options validate should throw an error on the "client" option with '{"unknownOption":true}' value 1`] = `
"ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
- options.client has an unknown property 'unknownOption'. These properties are valid:
object { logging?, overlay?, progress?, webSocketTransport?, webSocketURL? }"
object { logging?, overlay?, progress?, reconnect?, webSocketTransport?, webSocketURL? }"
`;

exports[`options validate should throw an error on the "client" option with '{"webSocketTransport":true}' value 1`] = `
"ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
- options.client should be one of these:
false | object { logging?, overlay?, progress?, webSocketTransport?, webSocketURL? }
false | object { logging?, overlay?, progress?, reconnect?, webSocketTransport?, webSocketURL? }
-> Allows to specify options for client script in the browser or disable client script.
-> Read more at https://webpack.js.org/configuration/dev-server/#devserverclient
Details:
Expand Down Expand Up @@ -171,7 +187,7 @@ exports[`options validate should throw an error on the "client" option with '{"w
exports[`options validate should throw an error on the "client" option with '{"webSocketURL":{"port":true}}' value 1`] = `
"ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
- options.client should be one of these:
false | object { logging?, overlay?, progress?, webSocketTransport?, webSocketURL? }
false | object { logging?, overlay?, progress?, reconnect?, webSocketTransport?, webSocketURL? }
-> Allows to specify options for client script in the browser or disable client script.
-> Read more at https://webpack.js.org/configuration/dev-server/#devserverclient
Details:
Expand All @@ -186,7 +202,7 @@ exports[`options validate should throw an error on the "client" option with '{"w
exports[`options validate should throw an error on the "client" option with '{"webSocketURL":{"username":123,"password":976}}' value 1`] = `
"ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
- options.client should be one of these:
false | object { logging?, overlay?, progress?, webSocketTransport?, webSocketURL? }
false | object { logging?, overlay?, progress?, reconnect?, webSocketTransport?, webSocketURL? }
-> Allows to specify options for client script in the browser or disable client script.
-> Read more at https://webpack.js.org/configuration/dev-server/#devserverclient
Details:
Expand All @@ -199,13 +215,13 @@ exports[`options validate should throw an error on the "client" option with '{"w
exports[`options validate should throw an error on the "client" option with 'whoops!' value 1`] = `
"ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
- options.client should be one of these:
false | object { logging?, overlay?, progress?, webSocketTransport?, webSocketURL? }
false | object { logging?, overlay?, progress?, reconnect?, webSocketTransport?, webSocketURL? }
-> Allows to specify options for client script in the browser or disable client script.
-> Read more at https://webpack.js.org/configuration/dev-server/#devserverclient
Details:
* options.client should be false.
* options.client should be an object:
object { logging?, overlay?, progress?, webSocketTransport?, webSocketURL? }"
object { logging?, overlay?, progress?, reconnect?, webSocketTransport?, webSocketURL? }"
`;

exports[`options validate should throw an error on the "compress" option with '' value 1`] = `
Expand Down
2 changes: 2 additions & 0 deletions test/cli/__snapshots__/basic.test.js.snap.webpack4
Expand Up @@ -69,6 +69,8 @@ Options:
--no-client-overlay-errors Negative 'client-overlay-errors' option.
--client-overlay-warnings Enables a full-screen overlay in the browser when there are compiler warnings.
--no-client-overlay-warnings Negative 'client-overlay-warnings' option.
--client-reconnect [value] Tells dev-server the number of times it should try to reconnect the client.
--no-client-reconnect Tells dev-server to not to try to connect the client.
--client-web-socket-url <value> Allows to specify URL to web socket server (useful when you're proxying dev server and client script does not always know where to connect to).
--client-web-socket-url-hostname <value> Tells clients connected to devServer to use the provided hostname.
--client-web-socket-url-port <value> Tells clients connected to devServer to use the provided port.
Expand Down
2 changes: 2 additions & 0 deletions test/cli/__snapshots__/basic.test.js.snap.webpack5
Expand Up @@ -69,6 +69,8 @@ Options:
--no-client-overlay-warnings Negative 'client-overlay-warnings' option.
--client-progress Prints compilation progress in percentage in the browser.
--no-client-progress Negative 'client-progress' option.
--client-reconnect [value] Tells dev-server the number of times it should try to reconnect the client.
--no-client-reconnect Negative 'client-reconnect' option.
--client-web-socket-transport <value> Allows to set custom web socket transport to communicate with dev server.
--client-web-socket-url <value> Allows to specify URL to web socket server (useful when you're proxying dev server and client script does not always know where to connect to).
--client-web-socket-url-hostname <value> Tells clients connected to devServer to use the provided hostname.
Expand Down