rwsdk
Version:
Build fast, server-driven webapps on Cloudflare with SSR, RSC, and realtime
69 lines (68 loc) • 2.59 kB
JavaScript
import debug from "debug";
const log = debug("rws-vite-plugin:hmr-stability");
let stabilityPromise = null;
let stabilityResolver = null;
let debounceTimer = null;
const DEBOUNCE_MS = 500;
function startWaitingForStability() {
if (!stabilityPromise) {
log("Starting to wait for server stability...");
stabilityPromise = new Promise((resolve) => {
stabilityResolver = resolve;
});
// Start the timer. If it fires, we're stable.
debounceTimer = setTimeout(finishWaiting, DEBOUNCE_MS);
}
}
function activityDetected() {
if (stabilityPromise) {
// If we're waiting for stability, reset the timer.
log("Activity detected, resetting stability timer.");
if (debounceTimer)
clearTimeout(debounceTimer);
debounceTimer = setTimeout(finishWaiting, DEBOUNCE_MS);
}
}
function finishWaiting() {
if (stabilityResolver) {
log("Server appears stable. Resolving promise.");
stabilityResolver();
}
stabilityPromise = null;
stabilityResolver = null;
debounceTimer = null;
}
export function hmrStabilityPlugin() {
return {
name: "rws-vite-plugin:hmr-stability",
// Monitor server activity
transform() {
activityDetected();
return null;
},
configureServer(server) {
// Return a function to ensure our middleware is placed after internal middlewares
return () => {
server.middlewares.use(async function rwsdkStaleBundleErrorHandler(err, req, res, next) {
if (err &&
typeof err.message === "string" &&
err.message.includes("new version of the pre-bundle")) {
log("Caught stale pre-bundle error. Waiting for server to stabilize...");
startWaitingForStability();
await stabilityPromise;
log("Server stabilized. Sending full-reload and redirecting.");
// Signal the client to do a full page reload.
server.environments.client.hot.send({
type: "full-reload",
});
// No need to wait further here, the stability promise handled it.
res.writeHead(307, { Location: req.url });
res.end();
return;
}
next(err);
});
};
},
};
}