Initial Commit
This commit is contained in:
commit
30231b4ce2
27
README.md
Normal file
27
README.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# fastify-min
|
||||||
|
|
||||||
|
## Description
|
||||||
|
Barebones fastify app to serve static content. Makes use of [icofonts](https://myrepos.xyz/Randy-Jordan/icofonts), [vanilla](https://myrepos.xyz/Randy-Jordan/vanilla), and [bejs](https://myrepos.xyz/Randy-Jordan/bejs). Basic boilerplate to create an app.
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
- [Description](#description)
|
||||||
|
- [Features](#features)
|
||||||
|
- [Credits / Resources](#credits--resources)
|
||||||
|
- [License](#license)
|
||||||
|
|
||||||
|
## Features / TODO
|
||||||
|
|
||||||
|
- [x] Serve static files
|
||||||
|
- [x] Server health route
|
||||||
|
- [x] Icofonts
|
||||||
|
|
||||||
|
|
||||||
|
## Credits / Resources
|
||||||
|
[Fastify Docs](https://fastify.dev/docs/latest/Guides/Getting-Started/)<br>
|
||||||
|
[Fastify Example App](https://github.com/delvedor/fastify-example)<br>
|
||||||
|
[Redis Docs](https://redis.io/)<br>
|
||||||
|
[Postgresql/PG_Admin](https://www.pgadmin.org/download/)
|
||||||
|
|
||||||
|
## License
|
||||||
|
This project is licensed under GPLv3 - see the [LICENSE](LICENSE) file for details.
|
24
app.js
Normal file
24
app.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import AutoLoad from '@fastify/autoload'
|
||||||
|
import path from 'path';
|
||||||
|
import { dirname } from 'path'
|
||||||
|
import { fileURLToPath } from 'url'
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url)
|
||||||
|
const __dirname = dirname(__filename)
|
||||||
|
|
||||||
|
// Setting up the autoloader for plugins and routes.
|
||||||
|
export default async function (fastify, opts) {
|
||||||
|
|
||||||
|
// Require all the plugins that we'll need in our application.
|
||||||
|
await fastify.register(AutoLoad, {
|
||||||
|
dir: path.join(__dirname,'plugins'),
|
||||||
|
options: Object.assign({}, opts)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Then, we'll load all of our routes.
|
||||||
|
await fastify.register(AutoLoad, {
|
||||||
|
dir: path.join(__dirname,'routes'),
|
||||||
|
dirNameRoutePrefix: false,
|
||||||
|
options: Object.assign({}, opts)
|
||||||
|
})
|
||||||
|
}
|
22
eslint.config.js
Normal file
22
eslint.config.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
|
||||||
|
import globals from "globals";
|
||||||
|
export default [
|
||||||
|
{
|
||||||
|
ignores: ["node_modules/"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
languageOptions: {
|
||||||
|
ecmaVersion: 2022,
|
||||||
|
sourceType: "module",
|
||||||
|
globals: {
|
||||||
|
...globals.node,
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
'no-unused-vars': 'warn',
|
||||||
|
'no-console': 'warn',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
25
index.js
Normal file
25
index.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import Fastify from 'fastify'
|
||||||
|
import App from './app.js' // Our app instance settings.
|
||||||
|
|
||||||
|
async function start () {
|
||||||
|
// Register our instance
|
||||||
|
const fastify = Fastify();
|
||||||
|
await fastify.register(App);
|
||||||
|
|
||||||
|
// Set up server settings.
|
||||||
|
const port = process.env.PORT || 3000
|
||||||
|
const address = process.env.ADDRESS || "localhost"
|
||||||
|
|
||||||
|
// Set up listener and on ready list all routes
|
||||||
|
fastify.listen({ port, address });
|
||||||
|
fastify.ready(() => {
|
||||||
|
const routes = fastify.printRoutes();
|
||||||
|
console.log(`Available Routes:\n${routes}`);
|
||||||
|
console.log(`Listening for connections on ${address}:${port}`);
|
||||||
|
})}
|
||||||
|
|
||||||
|
// Start the server and crash on error.
|
||||||
|
start().catch(err => {
|
||||||
|
console.error(err)
|
||||||
|
process.exit(1)
|
||||||
|
})
|
1405
package-lock.json
generated
Normal file
1405
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
21
package.json
Normal file
21
package.json
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"name": "fastify-min",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"description": "Barebones fastify app to serve static content",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
|
"start": "node --env-file=.env index.js"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@fastify/autoload": "^5.10.0",
|
||||||
|
"@fastify/static": "^7.0.4",
|
||||||
|
"fastify": "^4.28.1",
|
||||||
|
"fastify-healthcheck": "^4.4.0",
|
||||||
|
"ioredis": "^5.4.1",
|
||||||
|
"pg": "^8.12.0"
|
||||||
|
}
|
||||||
|
}
|
38
plugins/db.js
Normal file
38
plugins/db.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import fp from "fastify-plugin";
|
||||||
|
import pg from 'pg'
|
||||||
|
|
||||||
|
const { Pool } = pg
|
||||||
|
|
||||||
|
const pool = new Pool({
|
||||||
|
user: process.env.DB_USER,
|
||||||
|
host: process.env.DB_HOST,
|
||||||
|
database: process.env.DB_NAME,
|
||||||
|
password: process.env.DB_PASS,
|
||||||
|
port: process.env.DB_PORT,
|
||||||
|
})
|
||||||
|
|
||||||
|
async function database (fastify){
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
console.log(`Attempting to connect to ${process.env.DB_NAME}@${process.env.DB_HOST}:${process.env.DB_PORT}`);
|
||||||
|
const client = await pool.connect()
|
||||||
|
const res = await client.query('SELECT NOW()');
|
||||||
|
console.log("Connection success at:",res.rows[0].now)
|
||||||
|
await client.end()
|
||||||
|
|
||||||
|
|
||||||
|
} catch(err) {
|
||||||
|
console.error(err)
|
||||||
|
}
|
||||||
|
fastify.decorate('db', {pool})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default fp(database, {
|
||||||
|
// Protip: if you name your plugins, the stack trace in case of errors
|
||||||
|
// will be easier to read and other plugins can declare their dependency
|
||||||
|
// on this one. `fastify-autoload` will take care of loading the plugins
|
||||||
|
// in the correct order.
|
||||||
|
name: 'database'
|
||||||
|
})
|
26
plugins/redis.js
Normal file
26
plugins/redis.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import fp from 'fastify-plugin';
|
||||||
|
import Redis from 'ioredis';
|
||||||
|
|
||||||
|
// Fastify plugin for ioredis
|
||||||
|
async function redisPlugin(fastify) {
|
||||||
|
const redis = new Redis({
|
||||||
|
host: process.env.REDIS_HOST,
|
||||||
|
port: process.env.REDIS_PORT,
|
||||||
|
});
|
||||||
|
console.log(`Attempting to connect to redis@${process.env.REDIS_HOST}:${process.env.REDIS_PORT} ...`)
|
||||||
|
redis.on('connect', () => {
|
||||||
|
console.log(`Connection success to Redis at: ${new Date().toISOString()}`);
|
||||||
|
});
|
||||||
|
// Attach redis client to Fastify instance
|
||||||
|
fastify.decorate('redis', redis);
|
||||||
|
|
||||||
|
// Close redis connection on server shutdown
|
||||||
|
fastify.addHook('onClose', (app, done) => {
|
||||||
|
app.redis.quit();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export as a fastify plugin
|
||||||
|
export default fp(redisPlugin);
|
||||||
|
|
39
routes/publicRoutes.js
Normal file
39
routes/publicRoutes.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import fp from "fastify-plugin";
|
||||||
|
import healthcheck from 'fastify-healthcheck';
|
||||||
|
import Static from '@fastify/static'
|
||||||
|
import path from 'path';
|
||||||
|
import { dirname} from 'path'
|
||||||
|
import { fileURLToPath } from 'url'
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url)
|
||||||
|
const __dirname = dirname(__filename)
|
||||||
|
|
||||||
|
async function publicRoutes (fastify, opts) {
|
||||||
|
// Register healthcheck plugin
|
||||||
|
fastify.register(healthcheck, {
|
||||||
|
healthcheckUrl: '/health',
|
||||||
|
// healthcheckUrlDisable: true,
|
||||||
|
// healthcheckUrlAlwaysFail: true,
|
||||||
|
// underPressureOptions: { } // no under-pressure specific options set here
|
||||||
|
exposeUptime: true // enable, as a sample
|
||||||
|
})
|
||||||
|
|
||||||
|
await fastify.register(Static, {
|
||||||
|
root: path.join(__dirname, '..', 'static'),
|
||||||
|
prefix: '/' ,
|
||||||
|
wildcard: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
fastify.get("/*", async function(request, reply) {
|
||||||
|
return reply.send({404: "Not Found"})
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default fp(publicRoutes, {
|
||||||
|
// Protip: if you name your plugins, the stack trace in case of errors
|
||||||
|
// will be easier to read and other plugins can declare their dependency
|
||||||
|
// on this one. `fastify-autoload` will take care of loading the plugins
|
||||||
|
// in the correct order.
|
||||||
|
name: 'publicRoutes'
|
||||||
|
})
|
1
static/app.js
Normal file
1
static/app.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
console.log("Hello world!");
|
18
static/index.html
Normal file
18
static/index.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link rel="stylesheet" href="https://www.icofonts.com/style.css">
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
<title>Document</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="theme">
|
||||||
|
<h1>Hello World! <span class="icon-earth"></span> </h1>
|
||||||
|
|
||||||
|
<script src="app.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
129
static/style.css
Normal file
129
static/style.css
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
:root {
|
||||||
|
/* Font Sizes */
|
||||||
|
--fs-100: 0.625rem;
|
||||||
|
--fs-200: 0.75rem;
|
||||||
|
--fs-300: 0.875rem;
|
||||||
|
--fs-400: 1rem;
|
||||||
|
--fs-500: 1.125rem;
|
||||||
|
--fs-600: 1.25rem;
|
||||||
|
--fs-700: 1.5rem;
|
||||||
|
--fs-800: 2.5rem;
|
||||||
|
--fs-900: 3.5rem;
|
||||||
|
|
||||||
|
--fw-regular: 400;
|
||||||
|
--fw-semi-bold: 500;
|
||||||
|
--fw-bold: 700;
|
||||||
|
|
||||||
|
/* Color variables */
|
||||||
|
--clr-bg-ltheme: #edebe9;
|
||||||
|
--clr-text-ltheme: #1b1b1b;
|
||||||
|
--clr-accent-ltheme: #ff8000;
|
||||||
|
--clr-primary-ltheme: #d4d4d2;
|
||||||
|
--clr-secondary-ltheme: #babcbb;
|
||||||
|
--clr-link-ltheme: blue;
|
||||||
|
--clr-border-ltheme: blue;
|
||||||
|
|
||||||
|
--clr-bg-dtheme: #121212;
|
||||||
|
--clr-text-dtheme: #edebe9;
|
||||||
|
--clr-accent-dtheme: #3a3b9c;
|
||||||
|
--clr-primary-dtheme: #1b1b1b;
|
||||||
|
--clr-secondary-dtheme: #2d2d2d;
|
||||||
|
--clr-link-dtheme: blue;
|
||||||
|
--clr-border-dtheme: blue;
|
||||||
|
|
||||||
|
/* General Colors */
|
||||||
|
--black: #000; /* Black */
|
||||||
|
--white: #fff; /* White */
|
||||||
|
--clr-000: #636363;
|
||||||
|
--clr-100: #5A5A5A;
|
||||||
|
--clr-200: #515151;
|
||||||
|
--clr-300: #484848;
|
||||||
|
--clr-400: #3F3F3F;
|
||||||
|
--clr-500: #363636;
|
||||||
|
--clr-600: #2D2D2D;
|
||||||
|
--clr-700: #242424;
|
||||||
|
--clr-800: #1B1B1B;
|
||||||
|
--clr-900: #121212;
|
||||||
|
|
||||||
|
/* Semantic Colors */
|
||||||
|
--clr-success: #118c11;
|
||||||
|
--clr-info: #17a2b8;
|
||||||
|
--clr-warning: #ff8000;
|
||||||
|
--clr-danger: #d00000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CSS Resets */
|
||||||
|
*, *::before, *::after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove default margins. */
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set core root defaults */
|
||||||
|
html:focus-within {
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make images easiser to work with. */
|
||||||
|
img,picture,svg, video {
|
||||||
|
display: block;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove list styles (bullets/numbers) */
|
||||||
|
ol, ul, menu {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Form elements inherit font styles. */
|
||||||
|
input, textarea, button, select {
|
||||||
|
font: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Motion Reducted Media Query */
|
||||||
|
@media screen and
|
||||||
|
(prefers-reduced-motion: reduce),
|
||||||
|
(update: slow) {
|
||||||
|
* {
|
||||||
|
animation-duration: 0.001ms !important;
|
||||||
|
animation-iteration-count: 1 !important;
|
||||||
|
transition-duration: 0.001ms !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Screen reader friendly hidden. */
|
||||||
|
.visually-hidden:not(:focus):not(:active) {
|
||||||
|
border: 0;
|
||||||
|
clip: rect(0 0 0 0);
|
||||||
|
height: auto;
|
||||||
|
margin: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0;
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Body and core Themes */
|
||||||
|
|
||||||
|
body{
|
||||||
|
display: grid;
|
||||||
|
min-width: 100vw;
|
||||||
|
min-height: 100vh;
|
||||||
|
align-items: start;
|
||||||
|
line-height: 1.5rem;
|
||||||
|
background-color: var(--clr-bg-ltheme);
|
||||||
|
color: var(--clr-text-ltheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
body{
|
||||||
|
background-color: var(--clr-bg-dtheme);
|
||||||
|
color: var(--clr-text-dtheme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user