aboutsummaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/index.ts8
-rw-r--r--app/middlewares/blogs.ts28
-rw-r--r--app/middlewares/index.ts26
-rw-r--r--app/pages.ts112
-rw-r--r--app/routes/blog/router.ts5
-rw-r--r--app/routes/page/router.ts3
6 files changed, 108 insertions, 74 deletions
diff --git a/app/index.ts b/app/index.ts
index 664a751..7d73eb4 100644
--- a/app/index.ts
+++ b/app/index.ts
@@ -4,6 +4,8 @@ import * as page from './routes/page/router.js';
import * as blog from './routes/blog/router.js';
import { logger } from './logger.js'
import { PageDirectory } from './pages.js';
+import { directory } from './middlewares/index.js';
+import { blogs } from './middlewares/blogs.js';
dotenv.config()
@@ -16,6 +18,10 @@ app.use(express.static('static', {
maxAge: '1d'
}));
+const pageDirectory = new PageDirectory(process.env.PAGES_DIR);
+app.use(directory(pageDirectory));
+app.use(blogs(pageDirectory));
+
app.use(blog.router);
app.use(page.router);
@@ -36,7 +42,7 @@ const exit = () => {
})
}
-PageDirectory.rebuild('pages');
+pageDirectory.loadFromDisk();
process.on('SIGINT', exit);
process.on('SIGTERM', exit);
diff --git a/app/middlewares/blogs.ts b/app/middlewares/blogs.ts
index 8fd07c6..e1f5433 100644
--- a/app/middlewares/blogs.ts
+++ b/app/middlewares/blogs.ts
@@ -1,17 +1,19 @@
import { PageDirectory } from "../pages.js";
-export const blogs = ((req, res, next) => {
- let blogs = [];
- for (const page of Object.values(PageDirectory.pages)) {
- if (page.route.startsWith('blog/')) {
- blogs.push(page);
+export const blogs = (pageDirectory: PageDirectory) => {
+ return ((req, res, next) => {
+ let blogs = [];
+ for (const page of Object.values(pageDirectory.pages)) {
+ if (page.route.startsWith('blog/')) {
+ blogs.push(page);
+ }
}
- }
-
- blogs.sort((a, b) => {
- return b.metadata.date.getTime() - a.metadata.date.getTime();
+
+ blogs.sort((a, b) => {
+ return b.metadata.date.getTime() - a.metadata.date.getTime();
+ });
+
+ res.locals.blogs = blogs;
+ next();
});
-
- res.locals.blogs = blogs;
- next();
-});
+}
diff --git a/app/middlewares/index.ts b/app/middlewares/index.ts
index 81431ca..b5fcd34 100644
--- a/app/middlewares/index.ts
+++ b/app/middlewares/index.ts
@@ -1,16 +1,18 @@
import { PageDirectory } from "../pages.js";
-export const page = ((req, res, next) => {
- const path = req.originalUrl == "/" ? 'index' : req.originalUrl.substring(1);
- res.locals.path = path;
-
- const page = PageDirectory.get(path);
+export const directory = (pageDirectory: PageDirectory) => {
+ return ((req, res, next) => {
+ const path = req.originalUrl == "/" ? 'index' : req.originalUrl.substring(1);
+ res.locals.path = path;
+
+ const page = pageDirectory.get(path);
+
+ if (!page) {
+ next();
+ return;
+ }
- if (!page) {
+ res.locals.page = page;
next();
- return;
- }
-
- res.locals.page = page;
- next();
-});
+ });
+}
diff --git a/app/pages.ts b/app/pages.ts
index 3bef4a9..a7057da 100644
--- a/app/pages.ts
+++ b/app/pages.ts
@@ -3,9 +3,9 @@ import glob from 'glob';
import { logger } from './logger.js'
import { marked } from 'marked';
import matter from 'gray-matter';
+import chokidar from 'chokidar';
export function buildPage(page: Page) {
- logger.info(`Building ${page.path}`);
try {
const result = matter(page.raw);
const metadata = result.data;
@@ -19,61 +19,93 @@ export function buildPage(page: Page) {
}
}
-export namespace PageDirectory {
- export const pages: Record<string, Page> = {};
- export let lastBuild: number;
+function loadRaw(path: string): string {
+ return readFileSync(`${path}`, 'utf-8');
+}
+
+export class PageDirectory {
+ private pagesPath: string;
+
+ public pages: Record<string, Page> = {};
+ public lastFullBuild: number;
- export const rebuild = (pagePath: string): boolean => {
- for (const page in pages) {
- delete pages[page];
+ constructor(pagesPath: string) {
+ this.pagesPath = pagesPath;
+ }
+
+ public loadFromDisk = () => {
+ for (const page in this.pages) {
+ delete this.pages[page];
}
- const localPages = glob.sync(`**/*.{md,html}`, { cwd: pagePath })
+ const localPages = glob.sync(`**/*.{md,html}`, { cwd: this.pagesPath })
- // Load page content
- localPages.forEach(page => {
- let route = page.replace(/\.[^.]*$/,'')
- let name = /[^/]*$/.exec(route)[0];
- let path = `${pagePath}/${page}`
- let raw: string;
- try {
- raw = loadRaw(path);
- } catch (e) {
- logger.error(`Failed to read page ${path}: ${e.message}`);
- return;
- }
+ localPages.forEach(this.loadPage);
- pages[route] = {
- route: route,
- name: name,
- path: path,
- raw: raw,
- buildTime: 0,
- metadata: {
- title: "A Page"
- }
- }
+ this.lastFullBuild = Date.now();
+
+ const watcher = chokidar.watch('.', {
+ persistent: true,
+ cwd: this.pagesPath,
+ ignoreInitial: true,
});
- // Build pages
- Object.values(pages).forEach(page => buildPage(page));
+ const onPageChange = (page: string) => {
+ logger.info(`File ${page} has been modified`);
+ this.loadPage(page);
+ }
+
+ const onPageRemoval = (page: string) => {
+ logger.info(`File ${page} has been removed`);
+ this.removePage(page);
+ }
+
+ watcher.on('add', onPageChange);
+ watcher.on('change', onPageChange);
+ watcher.on('unlink', onPageRemoval);
+ }
+
+ public loadPage = (page: string): void => {
+ logger.info(`Building page ${page}`);
+ let route = page.replace(/\.[^.]*$/,'')
+ let name = /[^/]*$/.exec(route)[0];
+ let path = `${this.pagesPath}/${page}`
+ let raw: string;
+ try {
+ raw = loadRaw(path);
+ } catch (e) {
+ logger.error(`Failed to read page ${path}: ${e.message}`);
+ return;
+ }
- lastBuild = Date.now();
- return true;
+ this.pages[route] = {
+ route: route,
+ name: name,
+ path: path,
+ raw: raw,
+ buildTime: 0,
+ metadata: {
+ title: "A Page"
+ }
+ }
+
+ buildPage(this.pages[route]);
+ }
+
+ public removePage = (page: string): void => {
+ logger.info(`Unloading page ${page}`);
+ let route = page.replace(/\.[^.]*$/,'')
+ delete this.pages[route];
}
- export function get(name: string): Page {
- const page = pages[name];
+ public get(name: string): Page {
+ const page = this.pages[name];
if (!page) {
return undefined;
}
return page;
}
-
- function loadRaw(path: string): string {
- return readFileSync(`${path}`, 'utf-8');
- }
}
export type Page = {
diff --git a/app/routes/blog/router.ts b/app/routes/blog/router.ts
index bbd09d5..933946b 100644
--- a/app/routes/blog/router.ts
+++ b/app/routes/blog/router.ts
@@ -1,12 +1,7 @@
import express from 'express';
-import { page } from '../../middlewares/index.js';
-import { blogs } from '../../middlewares/blogs.js';
export const router = express.Router({ mergeParams: true });
-router.use('/blog/:page?', page);
-router.use('/blog/:page?', blogs);
-
router.get('/blog/:page?', (req, res, next) => {
let page = res.locals.page;
let index = !page || res.locals.path === 'blog';
diff --git a/app/routes/page/router.ts b/app/routes/page/router.ts
index 5c0a39b..b1b9bc1 100644
--- a/app/routes/page/router.ts
+++ b/app/routes/page/router.ts
@@ -1,10 +1,7 @@
import express from 'express';
-import { page } from '../../middlewares/index.js';
export const router = express.Router({ mergeParams: true });
-router.use('/:page?', page);
-
router.get('/:page?', (req, res, next) => {
let page = res.locals.page;
if (!page) {