Basic prototype of hot reloading mostly working with one controller.

main
Zed A. Shaw 9 months ago
parent 334fb1ff77
commit 9a730cd5d6
  1. 64
      commands/app.js
  2. 106
      package-lock.json
  3. 4
      package.json
  4. 1
      templates/header.html
  5. 23
      templates/todo.html

@ -1,8 +1,9 @@
import Fastify from "fastify";
import { restartable } from "@fastify/restartable";
import FastifyStatic from "@fastify/static";
import path from "path";
import { ToDo } from "../lib/models.js";
import fs from "fs";
import chokidar from "chokidar";
import nunjucks from "nunjucks";
export const description = "Runs your app.";
@ -11,22 +12,30 @@ export const options = [];
export const required = [];
const fastify = Fastify({
logger: true
});
let CONFIGURED = false;
// nunjucks does it's own reload so let it do that
nunjucks.configure("templates", { watch: true });
fastify.get("/todo", async (req, rep) => {
try {
const todo_list = await ToDo.all({});
const configure = async (fastify, opts) => {
// this is for exporing the problem of getting good error messages from templates
const result = nunjucks.render("templates/todo.html",
{todo_list, your_todos: "Your Todos"});
// MAGIC: this is how you trick the importer to reload modules
// that have changed. Since it uses a URL you can add a query
// to it, but that isn't parsed as the file. Using a date then
// tags the module as being "new" when it's still the same file
// TODO: maybe use fs timestamps instead?
// BUG: sometimes reload is too fast for vim and crashes
const controller = await import(`../controllers/todo.js?update=${new Date()}`);
rep.code(200)
.type("text/html")
.send(result);
const handler = new controller.Todo();
const app = fastify(opts);
// this is a sample that uses the handler we dynamic load
// to handle the /todo but not sure how to work the actual
// URL mappings for it. Also not sure about using classes
app.get("/todo", async (req, rep) => {
try {
await handler.get(req, rep);
} catch(error) {
console.error(error);
console.error(error.stack);
@ -34,16 +43,41 @@ fastify.get("/todo", async (req, rep) => {
}
});
fastify.register(FastifyStatic, {
app.register(FastifyStatic, {
root: path.join(path.resolve("."), 'static'),
prefix: '/', // optional: default '/'
constraints: {}, // optional: default {}
index: "index.html"
});
// this is from fastify/restartable
app.addHook('onClose', async () => {
if(!app.closingRestartable) {
console.log('closing the app because of restart')
} else{
console.log('closing the app because server is stopping')
}
})
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 {
await fastify.listen({port: 3000});
chokidar.watch(["lib","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);

106
package-lock.json generated

@ -21,6 +21,10 @@
},
"bin": {
"bando": "bando.js"
},
"devDependencies": {
"@fastify/restartable": "github:fastify/restartable",
"chokidar": "^3.6.0"
}
},
"node_modules/@fastify/accept-negotiator": {
@ -77,6 +81,15 @@
"helmet": "^7.0.0"
}
},
"node_modules/@fastify/restartable": {
"version": "2.2.0",
"resolved": "git+ssh://git@github.com/fastify/restartable.git#cd9c628df92283b8da2e5cff102d645c4c154a1b",
"dev": true,
"license": "MIT",
"dependencies": {
"fastify": "^4.16.3"
}
},
"node_modules/@fastify/send": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@fastify/send/-/send-2.1.0.tgz",
@ -346,6 +359,19 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/anymatch": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
"devOptional": true,
"dependencies": {
"normalize-path": "^3.0.0",
"picomatch": "^2.0.4"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/aproba": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz",
@ -431,6 +457,15 @@
}
]
},
"node_modules/binary-extensions": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
"devOptional": true,
"engines": {
"node": ">=8"
}
},
"node_modules/bindings": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
@ -610,6 +645,30 @@
"node": ">=8"
}
},
"node_modules/chokidar": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
"devOptional": true,
"dependencies": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
"glob-parent": "~5.1.2",
"is-binary-path": "~2.1.0",
"is-glob": "~4.0.1",
"normalize-path": "~3.0.0",
"readdirp": "~3.6.0"
},
"engines": {
"node": ">= 8.10.0"
},
"funding": {
"url": "https://paulmillr.com/funding/"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
}
},
"node_modules/chownr": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
@ -1052,6 +1111,20 @@
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"optional": true
},
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
"hasInstallScript": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@ -1353,6 +1426,18 @@
"node": ">= 0.10"
}
},
"node_modules/is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
"devOptional": true,
"dependencies": {
"binary-extensions": "^2.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/is-core-module": {
"version": "2.13.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
@ -1945,6 +2030,15 @@
"node": ">=6"
}
},
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"devOptional": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/npmlog": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz",
@ -2277,6 +2371,18 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
"devOptional": true,
"dependencies": {
"picomatch": "^2.2.1"
},
"engines": {
"node": ">=8.10.0"
}
},
"node_modules/real-require": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz",

@ -18,5 +18,9 @@
"knex-paginate": "^3.1.1",
"nunjucks": "^3.2.4",
"sqlite3": "^5.1.7"
},
"devDependencies": {
"@fastify/restartable": "github:fastify/restartable",
"chokidar": "^3.6.0"
}
}

@ -3,7 +3,6 @@
<html>
<head>
<script src="/alpine.js"></script>
<script src="/fsm.js"></script>
<title>Bandolier2</title>
<style>

@ -1,14 +1,7 @@
{% include "./header.html" %}
<h1>Your TODOs</h1>
<ol>
{% for todo in todo_list %}
<li>{{ todo.task }}</li>
{% else %}
<li>No TODO Items</li>
{% endfor %}
</ol>
<script>
</script>
<style>
.disabled {
@ -20,5 +13,17 @@
}
</style>
<h1>Your TODOs</h1>
<p>Welcome {{ name }}, here's your TODOs</p>
<ol>
{% for todo in todo_list %}
<li>{{ todo.task }}</li>
{% else %}
<li>No TODO Items</li>
{% endfor %}
</ol>
{% include "./footer.html" %}

Loading…
Cancel
Save