A basic but kind of scuffed Alpine version of the same functionality. Why is this so much more complicated?

main
Zed A. Shaw 10 months ago
parent f72fec3a5d
commit bafff1d25f
  1. 36
      commands/app.js
  2. 38
      controllers/todo_alpine.js
  3. 91
      package-lock.json
  4. 1
      package.json
  5. 3422
      static/axios.js
  6. 1
      static/axios.js.map
  7. 2
      templates/header.html
  8. 33
      templates/todo_alpine.html

@ -6,6 +6,7 @@ import path from "path";
import fs from "fs"; import fs from "fs";
import chokidar from "chokidar"; import chokidar from "chokidar";
import nunjucks from "nunjucks"; import nunjucks from "nunjucks";
import fg from "fast-glob";
export const description = "Runs your app."; export const description = "Runs your app.";
@ -22,23 +23,24 @@ const configure = async (fastify, opts) => {
const app = fastify(opts); const app = fastify(opts);
// forces reload of the modules // forces reload of the modules
const control_mod = await import(`../controllers/todo.js?update=${new Date()}`); for(let mod of fg.sync("controllers/*.js")) {
const control_mod = await import(`../${mod}?update=${new Date()}`);
// TODO: mappings are very simple for now // TODO: mappings are very simple for now
for(let [url, controller] of Object.entries(control_mod.default)) { for(let [url, controller] of Object.entries(control_mod.default)) {
const handler = new controller(); const handler = new controller();
// this goes through all the allowed verbs // this goes through all the allowed verbs
for(let verb of ["get", "post", "put", "delete"]) { for(let verb of ["get", "post", "put", "delete"]) {
if(verb in handler) { if(verb in handler) {
app[verb](`/${url}`, async (req, rep) => { app[verb](`/${url}`, async (req, rep) => {
try { try {
await handler[verb](req, rep); await handler[verb](req, rep);
} catch(error) { } catch(error) {
console.error(error); console.error(error);
console.error(error.stack); console.error(error.stack);
console.error(error.source); console.error(error.source);
} }
}); });
}
} }
} }
} }

@ -0,0 +1,38 @@
import { ToDo } from "../lib/models.js";
import nunjucks from "nunjucks";
// this can go away when I learn how to detect the request type
export class TodoIndex {
async get(req, rep) {
const todo_list = await ToDo.all({});
const result = nunjucks.render("todo_alpine.html", {name: "Zed"});
rep.code(200).type("text/html").send(result);
}
}
export class Todo {
async get(req, rep) {
const todo_list = await ToDo.all({});
rep.code(200).send(todo_list);
}
async post(req, rep) {
if(req.query.todo_id !== undefined) {
await ToDo.delete({id: req.query.todo_id});
} else {
await ToDo.insert({task: req.body.task});
}
// this is how you can prevent the annoying double submit
rep.code(200).send({message: "OK"});
}
}
// you use the export default to set the route URL?
// I mean, it works not sure if I like it though
export default {
todo_alpine: Todo,
todo_index: TodoIndex
};

91
package-lock.json generated

@ -12,6 +12,7 @@
"@fastify/formbody": "^7.4.0", "@fastify/formbody": "^7.4.0",
"@fastify/helmet": "^11.1.1", "@fastify/helmet": "^11.1.1",
"@fastify/static": "^7.0.0", "@fastify/static": "^7.0.0",
"axios": "^1.6.7",
"commander": "^12.0.0", "commander": "^12.0.0",
"fast-glob": "^3.3.2", "fast-glob": "^3.3.2",
"fastify": "^4.26.0", "fastify": "^4.26.0",
@ -425,6 +426,11 @@
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="
}, },
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/atomic-sleep": { "node_modules/atomic-sleep": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz",
@ -443,6 +449,16 @@
"fastq": "^1.6.1" "fastq": "^1.6.1"
} }
}, },
"node_modules/axios": {
"version": "1.6.7",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz",
"integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==",
"dependencies": {
"follow-redirects": "^1.15.4",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/balanced-match": { "node_modules/balanced-match": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@ -726,6 +742,17 @@
"resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz",
"integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==" "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ=="
}, },
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/commander": { "node_modules/commander": {
"version": "12.0.0", "version": "12.0.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-12.0.0.tgz", "resolved": "https://registry.npmjs.org/commander/-/commander-12.0.0.tgz",
@ -816,6 +843,14 @@
"node": ">=4.0.0" "node": ">=4.0.0"
} }
}, },
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/delegates": { "node_modules/delegates": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
@ -1065,6 +1100,25 @@
"node": ">=14" "node": ">=14"
} }
}, },
"node_modules/follow-redirects": {
"version": "1.15.5",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
"integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/foreground-child": { "node_modules/foreground-child": {
"version": "3.1.1", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
@ -1080,6 +1134,19 @@
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/forwarded": { "node_modules/forwarded": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
@ -1708,6 +1775,25 @@
"node": ">=10.0.0" "node": ">=10.0.0"
} }
}, },
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mimic-response": { "node_modules/mimic-response": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
@ -2311,6 +2397,11 @@
"node": ">= 0.10" "node": ">= 0.10"
} }
}, },
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"node_modules/pump": { "node_modules/pump": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",

@ -12,6 +12,7 @@
"@fastify/formbody": "^7.4.0", "@fastify/formbody": "^7.4.0",
"@fastify/helmet": "^11.1.1", "@fastify/helmet": "^11.1.1",
"@fastify/static": "^7.0.0", "@fastify/static": "^7.0.0",
"axios": "^1.6.7",
"commander": "^12.0.0", "commander": "^12.0.0",
"fast-glob": "^3.3.2", "fast-glob": "^3.3.2",
"fastify": "^4.26.0", "fastify": "^4.26.0",

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

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

@ -0,0 +1,33 @@
{% include "./header.html" %}
<h1>Your TODOs</h1>
<script src="/alpine.js"></script>
<script>
const new_task = async (todos, task) => {
// zero error handling but fine for now
await axios.post("/todo_alpine", {task});
return (await axios.get('/todo_alpine')).data;
}
</script>
<p>Welcome {{ name }}, here's your TODOs</p>
<div
x-data="{todos: []}"
x-init="todos = (await axios.get('/todo_alpine')).data">
<ol>
<template x-for="todo of todos">
<li x-text="todo.task"></li>
</template>
</ol>
<h4>Add a New TODO</h4>
<form action="/todo_index" @submit.prevent="todos = new_task(todos, task), task = ''" method="POST" x-data="{task: ''}">
<label for="task">Task</label>
<input name="task" x-model="task"></input>
<button type="button" @click="todos = new_task(todos, task), task = ''">Submit</button>
</form>
</div>
{% include "./footer.html" %}
Loading…
Cancel
Save