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