// This used to be based on waiting for a websocket to disconnect, but that was // flaky. Now we simply poll the shit out of the healthcheck endpoint. export function initDevReloader(healthzAddr, pollIntervalMs = 500) { // State model is implemented with variables and closures. let auto = true; let connected = false; let initialized = false; let interval; const button = document.createElement("button"); const indicator = document.createElement("div"); const label = document.createElement("div"); // Rolling our own reactivity: call this after state change to initialize or // update DOM view. function render() { button.style.appearance = "none"; button.style.background = "#fff"; button.style.border = "solid 1px #0002"; button.style.borderRadius = "999px"; button.style.padding = "1rem"; button.style.position = "fixed"; button.style.zIndex = "999"; button.style.bottom = "1rem"; button.style.left = "1rem"; button.style.opacity = "0.5"; button.style.boxShadow = "0 0.5rem 1rem #0002"; button.style.display = "flex"; button.style.cursor = "pointer"; button.style.alignItems = "center"; button.style.fontFamily = "sans-serif"; indicator.style.width = "8px"; indicator.style.height = "8px"; indicator.style.borderRadius = "999px"; indicator.style.background = connected ? "#06f" : "#f60"; label.style.marginLeft = "1rem"; label.innerText = auto ? "Disable auto-reload" : "Enable auto-reload"; } function toggleAuto() { auto = !auto; if (auto && !interval) { startInterval(); } else if (!auto && interval) { clearInterval(interval); interval = undefined; connected = false; initialized = false; } render(); } function startInterval() { interval = setInterval(function () { fetch(healthzAddr) .then(function () { if (!connected) { console.log("dev-reloader: connected"); if (auto && initialized) { globalThis.location.reload(); } connected = true; initialized = true; render(); } }) .catch(function () { if (connected) { console.log("dev-reloader: disconnected"); connected = false; render(); } }); }, pollIntervalMs); } render(); button.setAttribute("type", "button"); button.addEventListener("click", toggleAuto); button.appendChild(indicator); button.appendChild(label); document.body.appendChild(button); startInterval(); }