UNPKG

hotweby

Version:

Automatic hot-reloading webserver using websockets

76 lines 12.6 kB
#!/usr/bin/env node import { Option, program } from "commander"; import * as afs from "fs/promises"; import * as path from "path"; import { fileURLToPath } from "url"; import { createExpress, createReloadHtmlCode, createWebSocketServer, } from "./server.js"; const executrionDir = process.cwd(); const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); let registeredTriggers = []; const triggerReloads = () => { const reloads = registeredTriggers; registeredTriggers = []; for (const triggerReloadFunc of reloads) { triggerReloadFunc(); } }; const packageJson = JSON.parse(await afs.readFile(__dirname + "/../package.json", "utf-8")); program .name(packageJson.name) .description(packageJson.description) .version(packageJson.version) .addOption(new Option("-p, --port <number>", "hot reload server port") .argParser(value => Number(value)) .default(8080) .env("HOTWEBY_PORT")) .addOption(new Option("-d, --dir <string>", "Directory to serve html and other static files from.") .default(".") .env("HOTWEBY_PATH")) .addOption(new Option("-a, --auto-extension", "Try to auto default missing request file extensions. Checks if the requested dir containing a filename starting with requested name + '.'") .default(false) .env("HOTWEBY_AUTO_EXTENSION")) .addOption(new Option("-v, --verbose", "Enables verbose logging.") .default(false) .env("HOTWEBY_VERBOSE")) .action(async (str, options) => { str.dir = path.normalize(!str.dir.startsWith("/") ? executrionDir + "/" + str.dir : str.dir); console.info("Settings: ", str); const reloadHtmlCode = createReloadHtmlCode(); const autoExtension = Boolean(str.autoExtension ?? false); const verbose = Boolean(str.verbose ?? false); if (verbose) { console.info("Verbose mode is enabled."); } console.info("Auto extension resolution is " + (autoExtension ? "ON" : "OFF") + "."); try { const stat = await afs.stat(str.dir); if (!stat.isDirectory()) { throw new Error("'" + str.dir + "' is not a directory!"); } } catch (err) { if (err.code === "ENOENT") { console.error("Directory '" + str.dir + "' not exists!"); } } const app = createExpress(str.dir, reloadHtmlCode, autoExtension, verbose); const httpServer = app.listen(str.port, "0.0.0.0", async () => { console.info("Hot-HTML server is running on port '" + str.port + "'"); }); createWebSocketServer(httpServer, triggerFunc => registeredTriggers.push(triggerFunc)); const dirWatcher = afs.watch(str.dir); console.info("Wait for file in '" + str.dir + "' changes..."); for await (const x of dirWatcher) { console.info("Hot-HTML trigger reload..."); triggerReloads(); } }); program.parse(); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUVBLE9BQU8sRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLE1BQU0sV0FBVyxDQUFBO0FBQzNDLE9BQU8sS0FBSyxHQUFHLE1BQU0sYUFBYSxDQUFBO0FBQ2xDLE9BQU8sS0FBSyxJQUFJLE1BQU0sTUFBTSxDQUFBO0FBQzVCLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxLQUFLLENBQUE7QUFDbkMsT0FBTyxFQUNILGFBQWEsRUFDYixvQkFBb0IsRUFDcEIscUJBQXFCLEdBQ3hCLE1BQU0sYUFBYSxDQUFBO0FBRXBCLE1BQU0sYUFBYSxHQUFHLE9BQU8sQ0FBQyxHQUFHLEVBQUUsQ0FBQTtBQUNuQyxNQUFNLFVBQVUsR0FBRyxhQUFhLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQTtBQUNqRCxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFBO0FBSTFDLElBQUksa0JBQWtCLEdBQXFCLEVBQUUsQ0FBQTtBQUM3QyxNQUFNLGNBQWMsR0FBRyxHQUFHLEVBQUU7SUFDeEIsTUFBTSxPQUFPLEdBQUcsa0JBQWtCLENBQUE7SUFDbEMsa0JBQWtCLEdBQUcsRUFBRSxDQUFBO0lBQ3ZCLEtBQUssTUFBTSxpQkFBaUIsSUFBSSxPQUFPLEVBQUUsQ0FBQztRQUN0QyxpQkFBaUIsRUFBRSxDQUFBO0lBQ3ZCLENBQUM7QUFDTCxDQUFDLENBQUE7QUFFRCxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUMxQixNQUFNLEdBQUcsQ0FBQyxRQUFRLENBQUMsU0FBUyxHQUFHLGtCQUFrQixFQUFFLE9BQU8sQ0FBQyxDQUM5RCxDQUFBO0FBRUQsT0FBTztLQUNGLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDO0tBQ3RCLFdBQVcsQ0FBQyxXQUFXLENBQUMsV0FB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LEdBQUcsQ0FBQyxJQUFJO1lBQ1IsR0FBRyxDQUNWLENBQUE7SUFDTCxDQUFDLENBQ0osQ0FBQTtJQUVELHFCQUFxQixDQUFDLFVBQVUsRUFBRSxXQUFXLENBQUMsRUFBRSxDQUM1QyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQ3ZDLENBQUE7SUFFRCxNQUFNLFVBQVUsR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQTtJQUNyQyxPQUFPLENBQUMsSUFBSSxDQUNSLG9CQUFvQixHQUFHLEdBQUcsQ0FBQyxHQUFHLEdBQUcsY0FBYyxDQUNsRCxDQUFBO0lBRUQsSUFBSSxLQUFLLEVBQUUsTUFBTSxDQUFDLElBQUksVUFBVSxFQUFFLENBQUM7UUFDL0IsT0FBTyxDQUFDLElBQUksQ0FBQyw0QkFBNEIsQ0FBQyxDQUFBO1FBQzFDLGNBQWMsRUFBRSxDQUFBO0lBQ3BCLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQTtBQUVOLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQSIsInNvdXJjZXNDb250ZW50IjpbIiMhL3Vzci9iaW4vZW52IG5vZGVcblxuaW1wb3J0IHsgT3B0aW9uLCBwcm9ncmFtIH0gZnJvbSBcImNvbW1hbmRlclwiXG5pbXBvcnQgKiBhcyBhZnMgZnJvbSBcImZzL3Byb21pc2VzXCJcbmltcG9ydCAqIGFzIHBhdGggZnJvbSBcInBhdGhcIlxuaW1wb3J0IHsgZmlsZVVSTFRvUGF0aCB9IGZyb20gXCJ1cmxcIlxuaW1wb3J0IHtcbiAgICBjcmVhdGVFeHByZXNzLFxuICAgIGNyZWF0ZVJlbG9hZEh0bWxDb2RlLFxuICAgIGNyZWF0ZVdlYlNvY2tldFNlcnZlcixcbn0gZnJvbSBcIi4vc2VydmVyLmpzXCJcblxuY29uc3QgZXhlY3V0cmlvbkRpciA9IHByb2Nlc3MuY3dkKClcbmNvbnN0IF9fZmlsZW5hbWUgPSBmaWxlVVJMVG9QYXRoKGltcG9ydC5tZXRhLnVybClcbmNvbnN0IF9fZGlybmFtZSA9IHBhdGguZGlybmFtZShfX2ZpbGVuYW1lKVxuXG5leHBvcnQgdHlwZSBUcmlnZ2VySGFuZGxlciA9ICgpID0+IHZvaWRcblxubGV0IHJlZ2lzdGVyZWRUcmlnZ2VyczogVHJpZ2dlckhhbmRsZXJbXSA9IFtdXG5jb25zdCB0cmlnZ2VyUmVsb2FkcyA9ICgpID0+IHtcbiAgICBjb25zdCByZWxvYWRzID0gcmVnaXN0ZXJlZFRyaWdnZXJzXG4gICAgcmVnaXN0ZXJlZFRyaWdnZXJzID0gW11cbiAgICBmb3IgKGNvbnN0IHRyaWdnZXJSZWxvYWRGdW5jIG9mIHJlbG9hZHMpIHtcbiAgICAgICAgdHJpZ2dlclJlbG9hZEZ1bmMoKVxuICAgIH1cbn1cblxuY29uc3QgcGFja2FnZUpzb24gPSBKU09OLnBhcnNlKFxuICAgIGF3YWl0IGFmcy5yZWFkRmlsZShfX2Rpcm5hbWUgKyBcIi8uLi9wYWNrYWdlLmpzb25cIiwgXCJ1dGYtOFwiKSxcbilcblxucHJvZ3JhbVxuICAgIC5uYW1lKHBhY2thZ2VKc29uLm5hbWUpXG4gICAgLmRlc2NyaXB0aW9uKHBhY2thZ2VKc29uLmRlc2NyaXB0aW9uKVxuICAgIC52ZXJzaW9uKHBhY2thZ2VKc29uLnZlcnNpb24pXG4gICAgLmFkZE9wdGlvbihcbiAgICAgICAgbmV3IE9wdGlvbihcbiAgICAgICAgICAgIFwiLXAsIC0tcG9ydCA8bnVtYmVyPlwiLFxuICAgICAgICAgICAgXCJob3QgcmVsb2FkIHNlcnZlciBwb3J0XCIsXG4gICAgICAgIClcbiAgICAgICAgICAgIC5hcmdQYXJzZXIodmFsdWUgPT4gTnVtYmVyKHZhbHVlKSlcbiAgICAgICAgICAgIC5kZWZhdWx0KDgwODApXG4gICAgICAgICAgICAuZW52KFwiSE9UV0VCWV9QT1JUXCIpLFxuICAgIClcbiAgICAuYWRkT3B0aW9uKFxuICAgICAgICBuZXcgT3B0aW9uKFxuICAgICAgICAgICAgXCItZCwgLS1kaXIgPHN0cmluZz5cIixcbiAgICAgICAgICAgIFwiRGlyZWN0b3J5IHRvIHNlcnZlIGh0bWwgYW5kIG90aGVyIHN0YXRpYyBmaWxlcyBmcm9tLlwiLFxuICAgICAgICApXG4gICAgICAgICAgICAuZGVmYXVsdChcIi5cIilcbiAgICAgICAgICAgIC5lbnYoXCJIT1RXRUJZX1BBVEhcIiksXG4gICAgKVxuICAgIC5hZGRPcHRpb24oXG4gICAgICAgIG5ldyBPcHRpb24oXG4gICAgICAgICAgICBcIi1hLCAtLWF1dG8tZXh0ZW5zaW9uXCIsXG4gICAgICAgICAgICBcIlRyeSB0byBhdXRvIGRlZmF1bHQgbWlzc2luZyByZXF1ZXN0IGZpbGUgZXh0ZW5zaW9ucy4gQ2hlY2tzIGlmIHRoZSByZXF1ZXN0ZWQgZGlyIGNvbnRhaW5pbmcgYSBmaWxlbmFtZSBzdGFydGluZyB3aXRoIHJlcXVlc3RlZCBuYW1lICsgJy4nXCIsXG4gICAgICAgIClcbiAgICAgICAgICAgIC5kZWZhdWx0KGZhbHNlKVxuICAgICAgICAgICAgLmVudihcIkhPVFdFQllfQVVUT19FWFRFTlNJT05cIiksXG4gICAgKVxuICAgIC5hZGRPcHRpb24oXG4gICAgICAgIG5ldyBPcHRpb24oXCItdiwgLS12ZXJib3NlXCIsIFwiRW5hYmxlcyB2ZXJib3NlIGxvZ2dpbmcuXCIpXG4gICAgICAgICAgICAuZGVmYXVsdChmYWxzZSlcbiAgICAgICAgICAgIC5lbnYoXCJIT1RXRUJZX1ZFUkJPU0VcIiksXG4gICAgKVxuICAgIC5hY3Rpb24oYXN5bmMgKHN0ciwgb3B0aW9ucykgPT4ge1xuICAgICAgICBzdHIuZGlyID0gcGF0aC5ub3JtYWxpemUoXG4gICAgICAgICAgICAhc3RyLmRpci5zdGFydHNXaXRoKFwiL1wiKVxuICAgICAgICAgICAgICAgID8gZXhlY3V0cmlvbkRpciArIFwiL1wiICsgc3RyLmRpclxuICAgICAgICAgICAgICAgIDogc3RyLmRpcixcbiAgICAgICAgKVxuXG4gICAgICAgIGNvbnNvbGUuaW5mbyhcIlNldHRpbmdzOiBcIiwgc3RyKVxuXG4gICAgICAgIGNvbnN0IHJlbG9hZEh0bWxDb2RlID0gY3JlYXRlUmVsb2FkSHRtbENvZGUoKVxuXG4gICAgICAgIGNvbnN0IGF1dG9FeHRlbnNpb24gPSBCb29sZWFuKFxuICAgICAgICAgICAgc3RyLmF1dG9FeHRlbnNpb24gPz8gZmFsc2UsXG4gICAgICAgIClcblxuICAgICAgICBjb25zdCB2ZXJib3NlID0gQm9vbGVhbihzdHIudmVyYm9zZSA/PyBmYWxzZSlcblxuICAgICAgICBpZiAodmVyYm9zZSkge1xuICAgICAgICAgICAgY29uc29sZS5pbmZvKFwiVmVyYm9zZSBtb2RlIGlzIGVuYWJsZWQuXCIpXG4gICAgICAgIH1cblxuICAgICAgICBjb25zb2xlLmluZm8oXG4gICAgICAgICAgICBcIkF1dG8gZXh0ZW5zaW9uIHJlc29sdXRpb24gaXMgXCIgK1xuICAgICAgICAgICAgICAgIChhdXRvRXh0ZW5zaW9uID8gXCJPTlwiIDogXCJPRkZcIikgK1xuICAgICAgICAgICAgICAgIFwiLlwiLFxuICAgICAgICApXG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IHN0YXQgPSBhd2FpdCBhZnMuc3RhdChzdHIuZGlyKVxuXG4gICAgICAgICAgICBpZiAoIXN0YXQuaXNEaXJlY3RvcnkoKSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgICAgICAgICAgXCInXCIgKyBzdHIuZGlyICsgXCInIGlzIG5vdCBhIGRpcmVjdG9yeSFcIixcbiAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICB9XG4gICAgICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgICAgICBpZiAoZXJyLmNvZGUgPT09IFwiRU5PRU5UXCIpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKFxuICAgICAgICAgICAgICAgICAgICBcIkRpcmVjdG9yeSAnXCIgKyBzdHIuZGlyICsgXCInIG5vdCBleGlzdHMhXCIsXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgYXBwID0gY3JlYXRlRXhwcmVzcyhcbiAgICAgICAgICAgIHN0ci5kaXIsXG4gICAgICAgICAgICByZWxvYWRIdG1sQ29kZSxcbiAgICAgICAgICAgIGF1dG9FeHRlbnNpb24sXG4gICAgICAgICAgICB2ZXJib3NlLFxuICAgICAgICApXG5cbiAgICAgICAgY29uc3QgaHR0cFNlcnZlciA9IGFwcC5saXN0ZW4oXG4gICAgICAgICAgICBzdHIucG9ydCxcbiAgICAgICAgICAgIFwiMC4wLjAuMFwiLFxuICAgICAgICAgICAgYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcbiAgICAgICAgICAgICAgICAgICAgXCJIb3QtSFRNTCBzZXJ2ZXIgaXMgcnVubmluZyBvbiBwb3J0ICdcIiArXG4gICAgICAgICAgICAgICAgICAgICAgICBzdHIucG9ydCArXG4gICAgICAgICAgICAgICAgICAgICAgICBcIidcIixcbiAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICB9LFxuICAgICAgICApXG5cbiAgICAgICAgY3JlYXRlV2ViU29ja2V0U2VydmVyKGh0dHBTZXJ2ZXIsIHRyaWdnZXJGdW5jID0+XG4gICAgICAgICAgICByZWdpc3RlcmVkVHJpZ2dlcnMucHVzaCh0cmlnZ2VyRnVuYyksXG4gICAgICAgIClcblxuICAgICAgICBjb25zdCBkaXJXYXRjaGVyID0gYWZzLndhdGNoKHN0ci5kaXIpXG4gICAgICAgIGNvbnNvbGUuaW5mbyhcbiAgICAgICAgICAgIFwiV2FpdCBmb3IgZmlsZSBpbiAnXCIgKyBzdHIuZGlyICsgXCInIGNoYW5nZXMuLi5cIixcbiAgICAgICAgKVxuXG4gICAgICAgIGZvciBhd2FpdCAoY29uc3QgeCBvZiBkaXJXYXRjaGVyKSB7XG4gICAgICAgICAgICBjb25zb2xlLmluZm8oXCJIb3QtSFRNTCB0cmlnZ2VyIHJlbG9hZC4uLlwiKVxuICAgICAgICAgICAgdHJpZ2dlclJlbG9hZHMoKVxuICAgICAgICB9XG4gICAgfSlcblxucHJvZ3JhbS5wYXJzZSgpXG4iXX0=