sssg/src/plugins/dev.ts
2024-08-30 03:51:53 +03:00

97 lines
2.9 KiB
TypeScript

import type { Server, ServerWebSocket } from "bun";
import SSSG, { Plugin } from "..";
import * as fs from "fs";
import mime from "mime-types";
const script = `let reconnectTimeout,waitingForReconnect=!1;function connect(){console.log("[dev] connecting to dev server");var e=new WebSocket("ws://localhost:8080");e.addEventListener("message",e=>{"refresh"==e.data&&location.reload()}),e.addEventListener("open",()=>{console.log("[dev] connected"),waitingForReconnect&&location.reload()}),e.addEventListener("close",()=>{console.log("[dev] socket closed, restarting in 1s"),clearTimeout(reconnectTimeout),reconnectTimeout=setTimeout(()=>{connect(),waitingForReconnect=!0},1e3)})}window.addEventListener("load",()=>connect());`;
export default class DevPlugin extends Plugin {
build: undefined;
name = "dev";
rewriteTriggers = [];
renameTo = undefined;
longLasting = true;
server!: Server;
allConnections: ServerWebSocket<number>[] = [];
constructor(sssg: SSSG) {
super();
fs.watch(
sssg.inputFolder,
{
recursive: true,
},
async (e, f) => {
console.log("[dev] Noticed update in " + f + ", of type " + e + ".");
this.allConnections.forEach((z) => z.send("refresh"));
await sssg.build();
}
);
this.server = Bun.serve<number>({
fetch(req, server) {
const success = server.upgrade(req);
if (success) {
return undefined;
}
const url = new URL(req.url);
let cleanedPath = url.pathname;
if (cleanedPath == "/") cleanedPath = "/index.html";
if (cleanedPath.endsWith("/")) cleanedPath = cleanedPath.slice(0, -1);
let fsPath = sssg.outputFolder + cleanedPath;
if (fsPath.match(/\.\.\//g) !== null) {
return undefined;
}
let rawFile;
try {
rawFile = fs.readFileSync(fsPath);
} catch {
return new Response("404 Not Found", {
status: 404,
});
}
const type = fsPath.split(".").at(-1);
if (!type) return;
if (type == "html") {
rawFile = rawFile.toString().replace(
"<head>",
`<head><script>${script}</script>`
);
}
return new Response(rawFile, {
headers: {
"Cache-Control": "no-cache, no-store, must-revalidate",
"Pragma": "no-cache",
"Expires": "0",
"Content-Type": (mime.lookup(type) || "application/octet-stream") + "; charset=utf-8",
},
});
},
websocket: {
open: (ws) => {
ws.data = Math.random();
this.allConnections.push(ws);
},
message(ws, message) {},
close: (ws) => {
this.allConnections = this.allConnections.filter(
(z) => z.data != ws.data
);
},
},
port: 8080,
});
}
async rewriteFile(file: string, filePath: string) {
return undefined;
}
}