diff --git a/.changeset/brown-gorillas-notice.md b/.changeset/brown-gorillas-notice.md new file mode 100644 index 000000000..89d6c23d7 --- /dev/null +++ b/.changeset/brown-gorillas-notice.md @@ -0,0 +1,5 @@ +--- +"wmr": patch +--- + +when the hmr client disconnects attempt to reconnect with exponential backoff and a visibilityChange event-listener diff --git a/packages/wmr/src/plugins/wmr/client.js b/packages/wmr/src/plugins/wmr/client.js index ef017afae..7d7b68ab0 100644 --- a/packages/wmr/src/plugins/wmr/client.js +++ b/packages/wmr/src/plugins/wmr/client.js @@ -5,9 +5,11 @@ function log(...args) { const strip = url => url.replace(/[?&]t=\d+/g, ''); const addTimestamp = (url, time) => url + (/\?/.test(url) ? '&' : '?') + 't=' + time; - const resolve = url => new URL(url, location.origin).href; -let ws; + +let ws, + connectTimer, + connectDelay = 0; /** * @param {boolean} [needsReload] Force page to reload once it's connected @@ -19,10 +21,15 @@ function connect(needsReload) { ws.send(JSON.stringify(msg)); } + clearTimeout(connectTimer); ws.addEventListener('open', () => { log(`Connected to server.`); + connectDelay = 0; + clearTimeout(connectTimer); + connectTimer = undefined; + removeEventListener('visibilitychange', connectIfVisible); if (needsReload) { - window.location.reload(); + location.reload(); } else { queue.forEach(sendSocketMessage); queue = []; @@ -31,6 +38,22 @@ function connect(needsReload) { ws.addEventListener('message', handleMessage); ws.addEventListener('error', handleError); + ws.addEventListener('close', reconnect); +} + +function reconnect() { + connectDelay = Math.min(connectDelay * 2, 30000) || 500; + connectTimer = setTimeout(() => { + if (ws) ws.close(); + connect(false); + }, connectDelay); + addEventListener('visibilitychange', connectIfVisible); +} + +function connectIfVisible() { + if (document.visibilityState === 'visible') { + connect(false); + } } connect(); @@ -44,7 +67,7 @@ function handleMessage(e) { const data = JSON.parse(e.data); switch (data.type) { case 'reload': - window.location.reload(); + location.reload(); break; case 'update': if (errorOverlay) {