aboutsummaryrefslogtreecommitdiffstats
path: root/app/webserver/fileWatcher.ts
blob: 772ac1b7af2017bbe1ac0d52d8664ddb4a74ab3f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import chokidar, { FSWatcher } from 'chokidar';
import { logger } from '../logger.js';
import { PageDirectory } from '../builder/pageDirectory.js';
import { rebuildSinglePage } from '../builder/buildProject.js';
import path from 'path';
import fs from 'fs';

function attachPageEvents(watcher: FSWatcher, pages: PageDirectory) {
    const onPageChange = async (file: string) => {
        logger.info(`File ${file} has been modified, rebuilding...`);
        if (await rebuildSinglePage(file, pages)) {
            logger.info(`...done`);
        }
        logger.info(``);
    }

    const onPageRemoval = (file: string) => {
        logger.info(`File ${file} has been removed, deleting...`);
        const page = pages.get(file.replace(/\.[^.]*$/,''));
        if (!page) {
            logger.error(`Failed to find page for ${file}`);
            return;
        }
        const joinedPath = path.join(process.env.OUTPUT_DIR, `${page.route}.html`);
        try {
            fs.rmSync(joinedPath)
        } catch (e) {
            logger.error(`Failed to remove ${joinedPath}: ${e.message}`);
        }
        logger.info(`...done`);
        logger.info(``);
    }

    watcher.on('add', onPageChange);
    watcher.on('change', onPageChange);
    watcher.on('unlink', onPageRemoval);
}

function attachStaticEvents(watcher: FSWatcher) {
    const onStaticChange = async (file: string) => {
        logger.info(`Static file ${file} has been modified, copying...`);
        const joinedPath = path.join(process.env.STATIC_DIR, file);
        const joinedOutputPath = path.join(process.env.OUTPUT_DIR, 'static', file);
        try {
            fs.copyFileSync(joinedPath, joinedOutputPath);
            logger.info(`...done`);
        } catch (e) {
            logger.error(`Failed to copy ${joinedPath} to ${joinedOutputPath}: ${e.message}`);
        }
        logger.info(``);
    }

    const onStaticRemoval = (file: string) => {
        logger.info(`Static file ${file} has been removed, deleting...`);
        const joinedOutputPath = path.join(process.env.OUTPUT_DIR, 'static', file);
        try {
            fs.rmSync(joinedOutputPath)
            logger.info(`...done`);
        } catch (e) {
            logger.error(`Failed to remove ${joinedOutputPath}: ${e.message}`);
        }
        logger.info(``);
    }

    watcher.on('add', onStaticChange);
    watcher.on('change', onStaticChange);
    watcher.on('unlink', onStaticRemoval);
}

function attachViewEvents(watcher: FSWatcher, pages: PageDirectory) {
    const onViewChange = async (file: string) => {
        logger.info(`View ${file} has been modified, rebuilding pages with view...`);
        let pagesWithView = pages.getPages().filter(page => `${page.view}.ejs` === file);
        logger.info(`Found ${pagesWithView.length} pages with view ${file}`);
        for (const page of pagesWithView) {
            logger.info(`Rebuilding page ${page.route}...`);
            if (await rebuildSinglePage(page.originalPath, pages)) {
                logger.info(`...done`);
            }
        }
        logger.info(``);
    }

    const onViewRemoval = (file: string) => {
        logger.info(``);
        logger.info(`View ${file} has been removed`);
        logger.info(``);
    }

    watcher.on('add', onViewChange);
    watcher.on('change', onViewChange);
    watcher.on('unlink', onViewRemoval);
}

export const start = (pages: PageDirectory) => {
    const pagesWatcher = chokidar.watch('.', {
        persistent: true,
        cwd: process.env.PAGES_DIR,
        ignoreInitial: true,
    });
    const staticWatcher = chokidar.watch('.', {
        persistent: true,
        cwd: process.env.STATIC_DIR,
        ignoreInitial: true,
    });
    const viewsWatcher = chokidar.watch('.', {
        persistent: true,
        cwd: process.env.VIEWS_DIR,
        ignoreInitial: true,
    });

    attachPageEvents(pagesWatcher, pages);
    attachStaticEvents(staticWatcher);
    attachViewEvents(viewsWatcher, pages);
    
    const exitHandler = () => {
        logger.info(`Stopping file watcher...`);
        viewsWatcher.close();
        staticWatcher.close();
        pagesWatcher.close();
    }

    process.on('SIGINT', exitHandler);
    process.on('SIGTERM', exitHandler);
}