hotweby
Version:
Automatic hot-reloading webserver using websockets
138 lines • 19.1 kB
JavaScript
import express from "express";
import * as afs from "fs/promises";
import * as path from "path";
import { WebSocket, WebSocketServer } from "ws";
export function createReloadHtmlCode() {
const reloadHtmlScript = async () => {
console.log("[HOTWEBY]: connect websocket...");
const connectWs = () => {
const wsUrl = (location.protocol === "https:"
? "wss://"
: "ws://") + location.host;
const ws = new WebSocket(wsUrl);
ws.onopen = () => console.log("[HOTWEBY]: websocket connected");
ws.onclose = () => {
console.log("[HOTWEBY]: websocket closed, reloading...");
setTimeout(() => location.reload(), 100);
};
ws.onerror = err => {
console.error("[HOTWEBY]: websocket error, reloading...", err);
setTimeout(() => location.reload(), 1000);
};
};
connectWs();
};
const reloadHtmlCode = "" + reloadHtmlScript;
return "<script>\n(" + reloadHtmlCode + ")()\n</script>";
}
export function createExpress(targetDir, reloadHtmlCode, autoExtensionResolution, verbose) {
const app = express();
app.use(async (req, res, next) => {
if (!req.path.endsWith(".html") &&
!req.path.endsWith("/")) {
return next();
}
let reqPath = req.path;
if (reqPath.endsWith("/")) {
reqPath += "index.html";
}
try {
const data = await afs.readFile(targetDir + reqPath, "utf8");
res.status(200);
res.send(reloadHtmlCode + "\n" + data.toString());
verbose &&
console.info("Served html-file '" +
req.path +
"' from '" +
targetDir +
reqPath +
"'");
}
catch (err) {
console.error("Cant read requested html-file '" +
req.path +
"'" +
"\nfrom '" +
targetDir +
reqPath +
"':\n", err);
res.status(503);
res.setHeader("Content-Type", "text/plain");
res.setHeader("Retry-After", "5");
res.send("Cant read requested html-file '" +
req.path +
"'");
}
});
autoExtensionResolution &&
app.use(async (req, res, next) => {
const resolvedExtension = await autoResolveExtensions(req.url, targetDir, verbose);
if (resolvedExtension) {
req.url = resolvedExtension;
}
next();
});
app.use(express.static(targetDir));
return app;
}
export async function autoResolveExtensions(reqUrl, targetDir, verbose) {
while (reqUrl.startsWith("/")) {
reqUrl = reqUrl.slice(1);
}
if (reqUrl === "") {
return undefined;
}
try {
let realPath = targetDir + "/" + reqUrl;
if ((await pathType(realPath)) === "none") {
const files = await afs.readdir(path.dirname(realPath));
const baseName = path.basename(realPath);
for (const file of files) {
if (file.startsWith(baseName + ".")) {
verbose &&
console.info("Auto resolved extension for '" +
reqUrl +
"' to be '" +
path.dirname(reqUrl) +
"/" +
file +
"'");
return path.dirname(reqUrl) + "/" + file;
}
}
}
}
catch (err) {
verbose &&
console.error("Error while auto resolving extension for " +
reqUrl +
"\n", err);
}
return undefined;
}
export async function pathType(path) {
try {
const stat = await afs.stat(path);
return stat.isFile() ? "file" : "dir";
}
catch { }
return "none";
}
export function createWebSocketServer(httpServer, registerTrigger) {
const wsServer = new WebSocketServer({ noServer: true });
wsServer.on("connection", (ws, req) => {
registerTrigger(() => {
if (ws.readyState === ws.OPEN ||
ws.readyState === ws.CONNECTING) {
ws.close();
}
});
});
httpServer.on("upgrade", (req, socket, head) => {
wsServer.handleUpgrade(req, socket, head, ws => {
wsServer.emit("connection", ws, req);
});
});
return wsServer;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3NlcnZlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLE9BQU8sTUFBTSxTQUFTLENBQUE7QUFDN0IsT0FBTyxLQUFLLEdBQUcsTUFBTSxhQUFhLENBQUE7QUFFbEMsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUE7QUFDNUIsT0FBTyxFQUFFLFNBQVMsRUFBRSxlQUFlLEVBQUUsTUFBTSxJQUFJLENBQUE7QUFHL0MsTUFBTSxVQUFVLG9CQUFvQjtJQUNoQyxNQUFNLGdCQUFnQixHQUFHLEtBQUssSUFBSSxFQUFFO1FBQ2hDLE9BQU8sQ0FBQyxHQUFHLENBQUMsaUNBQWlDLENBQUMsQ0FBQTtRQUU5QyxNQUFNLFNBQVMsR0FBRyxHQUFHLEVBQUU7WUFDbkIsTUFBTSxLQUFLLEdBQ1AsQ0FBQyxRQUFRLENBQUMsUUFBUSxLQUFLLFFBQVE7Z0JBQzNCLENBQUMsQ0FBQyxRQUFRO2dCQUNWLENBQUMsQ0FBQyxPQUFPLENBQUMsR0FBRyxRQUFRLENBQUMsSUFBSSxDQUFBO1lBRWxDLE1BQU0sRUFBRSxHQUFHLElBQUksU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFBO1lBQy9CLEVBQUUsQ0FBQyxNQUFNLEdBQUcsR0FBRyxFQUFFLENBQ2IsT0FBTyxDQUFDLEdBQUcsQ0FBQyxnQ0FBZ0MsQ0FBQyxDQUFBO1lBQ2pELEVBQUUsQ0FBQyxPQUFPLEdBQUcsR0FBRyxFQUFFO2dCQUNkLE9BQU8sQ0FBQyxHQUFHLENBQ1AsMkNBQTJDLENBQzlDLENBQUE7Z0JBQ0QsVUFBVSxDQUFDLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxNQUFNLEVBQUUsRUFBRSxHQUFHLENBQUMsQ0FBQTtZQUM1QyxDQUFDLENBQUE7WUFDRCxFQUFFLENBQUMsT0FBTyxHQUFHLEdBQUcsQ0FBQyxFQUFFO2dCQUNmLE9BQU8sQ0FBQyxLQUFLLENBQ1QsMENBQTBDLEVBQzFDLEdBQUcsQ0FDTixD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QUcsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLEVBQUUsQ0FBQyxFQUFFO1lBQzNDLFFBQVEsQ0FBQyxJQUFJLENBQUMsWUFBWSxFQUFFLEVBQUUsRUFBRSxHQUFHLENBQUMsQ0FBQTtRQUN4QyxDQUFDLENBQUMsQ0FBQTtJQUNOLENBQUMsQ0FBQyxDQUFBO0lBRUYsT0FBTyxRQUFRLENBQUE7QUFDbkIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBleHByZXNzIGZyb20gXCJleHByZXNzXCJcbmltcG9ydCAqIGFzIGFmcyBmcm9tIFwiZnMvcHJvbWlzZXNcIlxuaW1wb3J0IHsgSW5jb21pbmdNZXNzYWdlLCBTZXJ2ZXIsIFNlcnZlclJlc3BvbnNlIH0gZnJvbSBcImh0dHBcIlxuaW1wb3J0ICogYXMgcGF0aCBmcm9tIFwicGF0aFwiXG5pbXBvcnQgeyBXZWJTb2NrZXQsIFdlYlNvY2tldFNlcnZlciB9IGZyb20gXCJ3c1wiXG5pbXBvcnQgeyBUcmlnZ2VySGFuZGxlciB9IGZyb20gXCIuL2luZGV4LmpzXCJcblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVJlbG9hZEh0bWxDb2RlKCkge1xuICAgIGNvbnN0IHJlbG9hZEh0bWxTY3JpcHQgPSBhc3luYyAoKSA9PiB7XG4gICAgICAgIGNvbnNvbGUubG9nKFwiW0hPVFdFQlldOiBjb25uZWN0IHdlYnNvY2tldC4uLlwiKVxuXG4gICAgICAgIGNvbnN0IGNvbm5lY3RXcyA9ICgpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHdzVXJsID1cbiAgICAgICAgICAgICAgICAobG9jYXRpb24ucHJvdG9jb2wgPT09IFwiaHR0cHM6XCJcbiAgICAgICAgICAgICAgICAgICAgPyBcIndzczovL1wiXG4gICAgICAgICAgICAgICAgICAgIDogXCJ3czovL1wiKSArIGxvY2F0aW9uLmhvc3RcblxuICAgICAgICAgICAgY29uc3Qgd3MgPSBuZXcgV2ViU29ja2V0KHdzVXJsKVxuICAgICAgICAgICAgd3Mub25vcGVuID0gKCkgPT5cbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcIltIT1RXRUJZXTogd2Vic29ja2V0IGNvbm5lY3RlZFwiKVxuICAgICAgICAgICAgd3Mub25jbG9zZSA9ICgpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgICAgICAgICAgICAgXCJbSE9UV0VCWV06IHdlYnNvY2tldCBjbG9zZWQsIHJlbG9hZGluZy4uLlwiLFxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICBzZXRUaW1lb3V0KCgpID0+IGxvY2F0aW9uLnJlbG9hZCgpLCAxMDApXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB3cy5vbmVycm9yID0gZXJyID0+IHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKFxuICAgICAgICAgICAgICAgICAgICBcIltIT1RXRUJZXTogd2Vic29ja2V0IGVycm9yLCByZWxvYWRpbmcuLi5cIixcbiAgICAgICAgICAgICAgICAgICAgZXJyLFxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICBzZXRUaW1lb3V0KCgpID0+IGxvY2F0aW9uLnJlbG9hZCgpLCAxMDAwKVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgY29ubmVjdFdzKClcbiAgICB9XG5cbiAgICBjb25zdCByZWxvYWRIdG1sQ29kZSA9IFwiXCIgKyByZWxvYWRIdG1sU2NyaXB0XG5cbiAgICByZXR1cm4gXCI8c2NyaXB0PlxcbihcIiArIHJlbG9hZEh0bWxDb2RlICsgXCIpKClcXG48L3NjcmlwdD5cIlxufVxuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlRXhwcmVzcyhcbiAgICB0YXJnZXREaXI6IHN0cmluZyxcbiAgICByZWxvYWRIdG1sQ29kZTogc3RyaW5nLFxuICAgIGF1dG9FeHRlbnNpb25SZXNvbHV0aW9uOiBib29sZWFuLFxuICAgIHZlcmJvc2U6IGJvb2xlYW4sXG4pIHtcbiAgICBjb25zdCBhcHAgPSBleHByZXNzKClcblxuICAgIGFwcC51c2UoYXN5bmMgKHJlcSwgcmVzLCBuZXh0KSA9PiB7XG4gICAgICAgIGlmIChcbiAgICAgICAgICAgICFyZXEucGF0aC5lbmRzV2l0aChcIi5odG1sXCIpICYmXG4gICAgICAgICAgICAhcmVxLnBhdGguZW5kc1dpdGgoXCIvXCIpXG4gICAgICAgICkge1xuICAgICAgICAgICAgcmV0dXJuIG5leHQoKVxuICAgICAgICB9XG5cbiAgICAgICAgbGV0IHJlcVBhdGggPSByZXEucGF0aFxuXG4gICAgICAgIGlmIChyZXFQYXRoLmVuZHNXaXRoKFwiL1wiKSkge1xuICAgICAgICAgICAgcmVxUGF0aCArPSBcImluZGV4Lmh0bWxcIlxuICAgICAgICB9XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IGRhdGEgPSBhd2FpdCBhZnMucmVhZEZpbGUoXG4gICAgICAgICAgICAgICAgdGFyZ2V0RGlyICsgcmVxUGF0aCxcbiAgICAgICAgICAgICAgICBcInV0ZjhcIixcbiAgICAgICAgICAgIClcbiAgICAgICAgICAgIHJlcy5zdGF0dXMoMjAwKVxuICAgICAgICAgICAgcmVzLnNlbmQocmVsb2FkSHRtbENvZGUgKyBcIlxcblwiICsgZGF0YS50b1N0cmluZygpKVxuXG4gICAgICAgICAgICB2ZXJib3NlICYmXG4gICAgICAgICAgICAgICAgY29uc29sZS5pbmZvKFxuICAgICAgICAgICAgICAgICAgICBcIlNlcnZlZCBodG1sLWZpbGUgJ1wiICtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlcS5wYXRoICtcbiAgICAgICAgICAgICAgICAgICAgICAgIFwiJyBmcm9tICdcIiArXG4gICAgICAgICAgICAgICAgICAgICAgICB0YXJnZXREaXIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVxUGF0aCArXG4gICAgICAgICAgICAgICAgICAgICAgICBcIidcIixcbiAgICAgICAgICAgICAgICApXG4gICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihcbiAgICAgICAgICAgICAgICBcIkNhbnQgcmVhZCByZXF1ZXN0ZWQgaHRtbC1maWxlICdcIiArXG4gICAgICAgICAgICAgICAgICAgIHJlcS5wYXRoICtcbiAgICAgICAgICAgICAgICAgICAgXCInXCIgK1xuICAgICAgICAgICAgICAgICAgICBcIlxcbmZyb20gJ1wiICtcbiAgICAgICAgICAgICAgICAgICAgdGFyZ2V0RGlyICtcbiAgICAgICAgICAgICAgICAgICAgcmVxUGF0aCArXG4gICAgICAgICAgICAgICAgICAgIFwiJzpcXG5cIixcbiAgICAgICAgICAgICAgICBlcnIsXG4gICAgICAgICAgICApXG4gICAgICAgICAgICByZXMuc3RhdHVzKDUwMylcbiAgICAgICAgICAgIHJlcy5zZXRIZWFkZXIoXCJDb250ZW50LVR5cGVcIiwgXCJ0ZXh0L3BsYWluXCIpXG4gICAgICAgICAgICByZXMuc2V0SGVhZGVyKFwiUmV0cnktQWZ0ZXJcIiwgXCI1XCIpXG4gICAgICAgICAgICByZXMuc2VuZChcbiAgICAgICAgICAgICAgICBcIkNhbnQgcmVhZCByZXF1ZXN0ZWQgaHRtbC1maWxlICdcIiArXG4gICAgICAgICAgICAgICAgICAgIHJlcS5wYXRoICtcbiAgICAgICAgICAgICAgICAgICAgXCInXCIsXG4gICAgICAgICAgICApXG4gICAgICAgIH1cbiAgICB9KVxuXG4gICAgYXV0b0V4dGVuc2lvblJlc29sdXRpb24gJiZcbiAgICAgICAgYXBwLnVzZShhc3luYyAocmVxLCByZXMsIG5leHQpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHJlc29sdmVkRXh0ZW5zaW9uID1cbiAgICAgICAgICAgICAgICBhd2FpdCBhdXRvUmVzb2x2ZUV4dGVuc2lvbnMoXG4gICAgICAgICAgICAgICAgICAgIHJlcS51cmwsXG4gICAgICAgICAgICAgICAgICAgIHRhcmdldERpcixcbiAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSxcbiAgICAgICAgICAgICAgICApXG5cbiAgICAgICAgICAgIGlmIChyZXNvbHZlZEV4dGVuc2lvbikge1xuICAgICAgICAgICAgICAgIHJlcS51cmwgPSByZXNvbHZlZEV4dGVuc2lvblxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBuZXh0KClcbiAgICAgICAgfSlcblxuICAgIGFwcC51c2UoZXhwcmVzcy5zdGF0aWModGFyZ2V0RGlyKSlcblxuICAgIHJldHVybiBhcHBcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGF1dG9SZXNvbHZlRXh0ZW5zaW9ucyhcbiAgICByZXFVcmw6IHN0cmluZyxcbiAgICB0YXJnZXREaXI6IHN0cmluZyxcbiAgICB2ZXJib3NlOiBib29sZWFuLFxuKTogUHJvbWlzZTxzdHJpbmcgfCB1bmRlZmluZWQ+IHtcbiAgICB3aGlsZSAocmVxVXJsLnN0YXJ0c1dpdGgoXCIvXCIpKSB7XG4gICAgICAgIHJlcVVybCA9IHJlcVVybC5zbGljZSgxKVxuICAgIH1cblxuICAgIGlmIChyZXFVcmwgPT09IFwiXCIpIHtcbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZFxuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICAgIGxldCByZWFsUGF0aCA9IHRhcmdldERpciArIFwiL1wiICsgcmVxVXJsXG4gICAgICAgIGlmICgoYXdhaXQgcGF0aFR5cGUocmVhbFBhdGgpKSA9PT0gXCJub25lXCIpIHtcbiAgICAgICAgICAgIGNvbnN0IGZpbGVzID0gYXdhaXQgYWZzLnJlYWRkaXIoXG4gICAgICAgICAgICAgICAgcGF0aC5kaXJuYW1lKHJlYWxQYXRoKSxcbiAgICAgICAgICAgIClcblxuICAgICAgICAgICAgY29uc3QgYmFzZU5hbWUgPSBwYXRoLmJhc2VuYW1lKHJlYWxQYXRoKVxuICAgICAgICAgICAgZm9yIChjb25zdCBmaWxlIG9mIGZpbGVzKSB7XG4gICAgICAgICAgICAgICAgaWYgKGZpbGUuc3RhcnRzV2l0aChiYXNlTmFtZSArIFwiLlwiKSkge1xuICAgICAgICAgICAgICAgICAgICB2ZXJib3NlICYmXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmluZm8oXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJBdXRvIHJlc29sdmVkIGV4dGVuc2lvbiBmb3IgJ1wiICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVxVXJsICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXCInIHRvIGJlICdcIiArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdGguZGlybmFtZShyZXFVcmwpICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXCIvXCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXCInXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBwYXRoLmRpcm5hbWUocmVxVXJsKSArIFwiL1wiICsgZmlsZVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICB2ZXJib3NlICYmXG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKFxuICAgICAgICAgICAgICAgIFwiRXJyb3Igd2hpbGUgYXV0byByZXNvbHZpbmcgZXh0ZW5zaW9uIGZvciBcIiArXG4gICAgICAgICAgICAgICAgICAgIHJlcVVybCArXG4gICAgICAgICAgICAgICAgICAgIFwiXFxuXCIsXG4gICAgICAgICAgICAgICAgZXJyLFxuICAgICAgICAgICAgKVxuICAgIH1cblxuICAgIHJldHVybiB1bmRlZmluZWRcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHBhdGhUeXBlKFxuICAgIHBhdGg6IHN0cmluZyxcbik6IFByb21pc2U8XCJmaWxlXCIgfCBcImRpclwiIHwgXCJub25lXCI+IHtcbiAgICB0cnkge1xuICAgICAgICBjb25zdCBzdGF0ID0gYXdhaXQgYWZzLnN0YXQocGF0aClcbiAgICAgICAgcmV0dXJuIHN0YXQuaXNGaWxlKCkgPyBcImZpbGVcIiA6IFwiZGlyXCJcbiAgICB9IGNhdGNoIHt9XG4gICAgcmV0dXJuIFwibm9uZVwiXG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVXZWJTb2NrZXRTZXJ2ZXIoXG4gICAgaHR0cFNlcnZlcjogU2VydmVyPFxuICAgICAgICB0eXBlb2YgSW5jb21pbmdNZXNzYWdlLFxuICAgICAgICB0eXBlb2YgU2VydmVyUmVzcG9uc2VcbiAgICA+LFxuICAgIHJlZ2lzdGVyVHJpZ2dlcjogKHRyaWdnZXJIYW5kbGVyOiBUcmlnZ2VySGFuZGxlcikgPT4gdm9pZCxcbikge1xuICAgIGNvbnN0IHdzU2VydmVyID0gbmV3IFdlYlNvY2tldFNlcnZlcih7IG5vU2VydmVyOiB0cnVlIH0pXG4gICAgd3NTZXJ2ZXIub24oXCJjb25uZWN0aW9uXCIsICh3cywgcmVxKSA9PiB7XG4gICAgICAgIHJlZ2lzdGVyVHJpZ2dlcigoKSA9PiB7XG4gICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgd3MucmVhZHlTdGF0ZSA9PT0gd3MuT1BFTiB8fFxuICAgICAgICAgICAgICAgIHdzLnJlYWR5U3RhdGUgPT09IHdzLkNPTk5FQ1RJTkdcbiAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgIHdzLmNsb3NlKClcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSlcbiAgICB9KVxuXG4gICAgaHR0cFNlcnZlci5vbihcInVwZ3JhZGVcIiwgKHJlcSwgc29ja2V0LCBoZWFkKSA9PiB7XG4gICAgICAgIHdzU2VydmVyLmhhbmRsZVVwZ3JhZGUocmVxLCBzb2NrZXQsIGhlYWQsIHdzID0+IHtcbiAgICAgICAgICAgIHdzU2VydmVyLmVtaXQoXCJjb25uZWN0aW9uXCIsIHdzLCByZXEpXG4gICAgICAgIH0pXG4gICAgfSlcblxuICAgIHJldHVybiB3c1NlcnZlclxufVxuIl19