Files
haopengzhan 8c0b04db0e feat: initial release of pengzhan.dev personal editorial blog platform
- Editorial web platform built with Node.js, Express, EJS, and Vanilla CSS
- Markdown content engine with YAML frontmatter, bilingual variants, and hot-reload watcher
- Unified SQLite with FTS5 search indexing, query logging, and schema filters
- Centered editorial post layout with margin-docked left TOC and mobile bottom sheet
- WordPress-grade comment system with moderation dashboard and bulk operations under /guanli
- Complete SEO suite (JSON-LD structured data, RSS/Atom feeds, XML sitemap, robots.txt)
- CI/CD workflows for linting, security audits (Gitleaks), automated tests, and Docker releases
2026-09-16 23:08:53 -07:00

61 lines
1.8 KiB
JavaScript

const chokidar = require('chokidar');
const path = require('path');
const contentService = require('./content');
const pluginManager = require('./plugin-manager');
const { loadSiteConfig } = require('../config');
class WatcherService {
constructor() {
this.watcher = null;
this.debounceTimer = null;
}
start(contentDir, app) {
console.log(`[Watcher] Starting filesystem watcher on ${contentDir}`);
this.watcher = chokidar.watch(contentDir, {
ignored: [
/(^|[\/\\])\../, // dotfiles
/(^|[\/\\])data([\/\\]|$)/, // ignore entire data/ directory (site.db, journals, etc.)
/\.db(-journal|-wal|-shm)?$/, // sqlite database files
/node_modules/
],
persistent: true,
ignoreInitial: true,
awaitWriteFinish: {
stabilityThreshold: 300,
pollInterval: 100
}
});
const triggerReload = (event, filePath) => {
const relative = path.relative(contentDir, filePath);
console.log(`[Watcher] Detected ${event} on ${relative}`);
clearTimeout(this.debounceTimer);
this.debounceTimer = setTimeout(() => {
try {
const freshConfig = loadSiteConfig();
pluginManager.loadPlugins(contentDir, app, freshConfig);
contentService.reload();
console.log(`[Watcher] Hot reload finished successfully.`);
} catch (err) {
console.error(`[Watcher] Error during hot reload:`, err);
}
}, 250);
};
this.watcher.on('add', (p) => triggerReload('add', p));
this.watcher.on('change', (p) => triggerReload('change', p));
this.watcher.on('unlink', (p) => triggerReload('unlink', p));
}
close() {
if (this.watcher) {
this.watcher.close();
}
}
}
module.exports = new WatcherService();