import Fastify from "fastify"; import { restartable } from "@fastify/restartable"; import FastifyStatic from "@fastify/static"; import Formbody from "@fastify/formbody"; import path from "path"; import fs from "fs"; import chokidar from "chokidar"; import nunjucks from "nunjucks"; import fg from "fast-glob"; export const description = "Runs your app."; export const options = []; export const required = []; let CONFIGURED = false; // nunjucks does it's own reload so let it do that nunjucks.configure("pages", { watch: true }); const load_mod = async (app, mod) => { const control_mod = await import(`../${mod}?update=${Date.now()}`); const pf = path.parse(mod); const url = `/${pf.name}`; for(let verb of ["get", "post", "put", "delete"]) { const handler = control_mod[verb]; if(handler !== undefined) { app[verb](url, async (req, rep) => { try { await handler(req, rep); } catch(error) { console.error(error); console.error(error.stack); console.error(error.source); } }); } } } const configure = async (fastify, opts) => { const app = fastify(opts); // forces reload of the modules for(let mod of fg.sync("{api,controllers}/*.js")) { await load_mod(app, mod); } app.register(Formbody); app.get("/*", (req, rep) => { try { const target = path.resolve(path.join("pages", req.url)); const index = path.resolve(path.join("pages", req.url, "index.html")); if(fs.existsSync(index) && !fs.statSync(index).isDirectory()) { const result = nunjucks.render(index); rep.code(200).type("text/html").send(result); } else if(fs.existsSync(target)) { const fname = req.url.slice(1); const result = nunjucks.render(fname); rep.code(200).type("text/html").send(result); } else { console.error("404 NOT FOUND", target, "NO INDEX", index); rep.code(404).type("text/html").send("Not Found"); } } catch(error) { console.error(error); rep.code(500).type("text/html").send("Internal Server Error"); } }); app.register(FastifyStatic, { root: path.join(path.resolve("."), 'static'), prefix: '/static', constraints: {}, index: "index.html" }); return app; } const app = await await restartable(configure, { logger: true}); const host = await app.listen({port: 3000}); const reload = () => { if(CONFIGURED) { app.restart(); } } export const main = async (arg, opts) => { try { chokidar.watch(["lib","api", "pages", "commands","controllers","static","migrations","tests"]) .on("add", path => reload()) .on("change", path => reload()) .on("unlink", path => reload()) .on("ready", () => CONFIGURED = true); } catch(err) { fastify.log.error(err); process.exit(1); } }