@rettangoli/sites 0.2.7 ā 1.0.0-rc10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +201 -93
- package/package.json +8 -8
- package/sites/README.md +67 -0
- package/sites/partials/docs-mobile-nav.yaml +7 -0
- package/sites/partials/docs-sidebar.yaml +1 -0
- package/sites/partials/mobile-nav.yaml +10 -0
- package/sites/partials/navbar.yaml +7 -0
- package/sites/partials/seo.yaml +11 -0
- package/sites/templates/base.yaml +25 -0
- package/sites/templates/docs.yaml +37 -0
- package/src/builtinTemplateFunctions.js +163 -0
- package/src/cli/build.js +17 -9
- package/src/cli/init.js +5 -5
- package/src/cli/watch.js +154 -180
- package/src/createSiteBuilder.js +398 -105
- package/src/markdownItAsync.js +104 -0
- package/src/rtglMarkdown.js +162 -13
- package/src/screenshotRunner.js +5 -169
- package/src/utils/loadSiteConfig.js +333 -36
- package/templates/default/README.md +57 -25
- package/templates/default/data/site.yaml +3 -0
- package/templates/default/pages/blog.yaml +1 -1
- package/templates/default/pages/index.yaml +1 -1
- package/templates/default/partials/footer.yaml +1 -1
- package/templates/default/partials/header.yaml +1 -1
- package/templates/default/sites.config.yaml +24 -0
- package/templates/default/templates/base.yaml +5 -3
- package/templates/default/templates/post.yaml +6 -4
- package/src/screenshot.js +0 -250
- package/templates/default/package.json +0 -14
- package/templates/default/sites.config.js +0 -9
package/src/cli/watch.js
CHANGED
|
@@ -1,70 +1,98 @@
|
|
|
1
1
|
import fs, { watch, existsSync } from 'node:fs';
|
|
2
2
|
import http from 'node:http';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
-
import { pathToFileURL } from 'node:url';
|
|
5
4
|
import { WebSocketServer } from 'ws';
|
|
6
5
|
import { buildSite } from './build.js';
|
|
7
|
-
import { createScreenshotCapture } from '../screenshot.js';
|
|
8
6
|
import { loadSiteConfig } from '../utils/loadSiteConfig.js';
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
ws.onopen = () => {
|
|
18
|
-
console.log('ā
WebSocket connected');
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
ws.onmessage = (event) => {
|
|
22
|
-
console.log('šØ Message received:', event.data);
|
|
23
|
-
const data = JSON.parse(event.data);
|
|
24
|
-
|
|
25
|
-
if (data.type === 'reload-current') {
|
|
26
|
-
console.log('š Fetching updated page...');
|
|
27
|
-
|
|
8
|
+
const RELOAD_MODES = new Set(['body', 'full']);
|
|
9
|
+
|
|
10
|
+
export function createClientScript(reloadMode = 'body') {
|
|
11
|
+
const shouldUseBodyReplacement = reloadMode === 'body';
|
|
12
|
+
const reloadSnippet = shouldUseBodyReplacement
|
|
13
|
+
? `
|
|
28
14
|
// Fetch the current page's HTML
|
|
29
15
|
fetch(window.location.href)
|
|
30
16
|
.then(response => response.text())
|
|
31
17
|
.then(html => {
|
|
32
|
-
console.log('š Received updated HTML');
|
|
33
|
-
|
|
34
18
|
// Parse the new HTML
|
|
35
19
|
const parser = new DOMParser();
|
|
36
20
|
const newDoc = parser.parseFromString(html, 'text/html');
|
|
37
|
-
|
|
21
|
+
|
|
38
22
|
// Replace entire body content
|
|
39
23
|
document.body.innerHTML = newDoc.body.innerHTML;
|
|
40
|
-
|
|
41
|
-
console.log('ā
Hot reload complete');
|
|
42
24
|
})
|
|
43
25
|
.catch(err => {
|
|
44
|
-
console.error('
|
|
26
|
+
console.error('Hot reload failed:', err);
|
|
45
27
|
// Fallback to full reload
|
|
46
28
|
window.location.reload();
|
|
47
29
|
});
|
|
30
|
+
`
|
|
31
|
+
: `
|
|
32
|
+
window.location.reload();
|
|
33
|
+
`;
|
|
34
|
+
|
|
35
|
+
return `
|
|
36
|
+
<script>
|
|
37
|
+
(function() {
|
|
38
|
+
const wsProtocol = location.protocol === 'https:' ? 'wss://' : 'ws://';
|
|
39
|
+
const ws = new WebSocket(wsProtocol + location.host);
|
|
40
|
+
|
|
41
|
+
ws.onmessage = (event) => {
|
|
42
|
+
const data = JSON.parse(event.data);
|
|
43
|
+
|
|
44
|
+
if (data.type === 'reload-current') {
|
|
45
|
+
${reloadSnippet}
|
|
48
46
|
}
|
|
49
47
|
};
|
|
50
|
-
|
|
48
|
+
|
|
51
49
|
ws.onclose = () => {
|
|
52
|
-
console.log('ā Lost connection to dev server. Reloading in 1s...');
|
|
53
50
|
setTimeout(() => location.reload(), 1000);
|
|
54
51
|
};
|
|
55
|
-
|
|
56
|
-
ws.onerror = (err) => {
|
|
57
|
-
console.error('ā WebSocket error:', err);
|
|
58
|
-
};
|
|
59
52
|
})();
|
|
60
53
|
</script>
|
|
61
54
|
`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function getContentType(ext) {
|
|
58
|
+
const types = {
|
|
59
|
+
'.html': 'text/html; charset=utf-8',
|
|
60
|
+
'.css': 'text/css; charset=utf-8',
|
|
61
|
+
'.js': 'application/javascript; charset=utf-8',
|
|
62
|
+
'.json': 'application/json; charset=utf-8',
|
|
63
|
+
'.txt': 'text/plain; charset=utf-8',
|
|
64
|
+
'.md': 'text/plain; charset=utf-8',
|
|
65
|
+
'.png': 'image/png',
|
|
66
|
+
'.jpg': 'image/jpeg',
|
|
67
|
+
'.jpeg': 'image/jpeg',
|
|
68
|
+
'.gif': 'image/gif',
|
|
69
|
+
'.svg': 'image/svg+xml',
|
|
70
|
+
'.ico': 'image/x-icon',
|
|
71
|
+
'.webp': 'image/webp'
|
|
72
|
+
};
|
|
73
|
+
return types[ext] || 'application/octet-stream';
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function createLogger(quiet = false) {
|
|
77
|
+
return {
|
|
78
|
+
log: (...args) => {
|
|
79
|
+
if (!quiet) {
|
|
80
|
+
console.log(...args);
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
error: (...args) => {
|
|
84
|
+
console.error(...args);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
}
|
|
62
88
|
|
|
63
89
|
class DevServer {
|
|
64
|
-
constructor(port = 3001) {
|
|
90
|
+
constructor(port = 3001, siteDir = '_site', logger = createLogger(false), reloadMode = 'body') {
|
|
65
91
|
this.port = port;
|
|
66
92
|
this.clients = new Set();
|
|
67
|
-
this.siteDir =
|
|
93
|
+
this.siteDir = siteDir;
|
|
94
|
+
this.logger = logger;
|
|
95
|
+
this.clientScript = createClientScript(reloadMode);
|
|
68
96
|
}
|
|
69
97
|
|
|
70
98
|
start() {
|
|
@@ -75,39 +103,29 @@ class DevServer {
|
|
|
75
103
|
|
|
76
104
|
// Create WebSocket server
|
|
77
105
|
this.wss = new WebSocketServer({ server: this.httpServer });
|
|
78
|
-
console.log('WebSocket server created');
|
|
79
106
|
|
|
80
107
|
this.wss.on('connection', (ws) => {
|
|
81
|
-
console.log('ā
Client connected. Total clients:', this.clients.size + 1);
|
|
82
108
|
this.clients.add(ws);
|
|
83
109
|
|
|
84
110
|
ws.on('close', () => {
|
|
85
|
-
console.log('ā Client disconnected. Remaining clients:', this.clients.size - 1);
|
|
86
111
|
this.clients.delete(ws);
|
|
87
112
|
});
|
|
88
113
|
|
|
89
114
|
ws.on('error', (err) => {
|
|
90
|
-
|
|
115
|
+
this.logger.error('WebSocket error:', err);
|
|
91
116
|
this.clients.delete(ws);
|
|
92
117
|
});
|
|
93
118
|
});
|
|
94
119
|
|
|
95
120
|
// Start listening
|
|
96
121
|
this.httpServer.listen(this.port, '0.0.0.0', () => {
|
|
97
|
-
|
|
98
|
-
console.log(` > Local: http://localhost:${this.port}/`);
|
|
99
|
-
console.log(` > Network: http://0.0.0.0:${this.port}/\n`);
|
|
100
|
-
console.log(` Hot reload enabled (body replacement)\n`);
|
|
122
|
+
this.logger.log(`Dev server: http://localhost:${this.port}/`);
|
|
101
123
|
});
|
|
102
124
|
}
|
|
103
125
|
|
|
104
126
|
handleRequest(req, res) {
|
|
105
127
|
const urlParts = req.url.split('?');
|
|
106
128
|
let urlPath = urlParts[0];
|
|
107
|
-
const queryString = urlParts[1] || '';
|
|
108
|
-
|
|
109
|
-
// Check if this is a screenshot request
|
|
110
|
-
const isScreenshotRequest = queryString.includes('screenshot=true');
|
|
111
129
|
|
|
112
130
|
// Default to index.html for root
|
|
113
131
|
if (urlPath === '/') {
|
|
@@ -150,7 +168,7 @@ class DevServer {
|
|
|
150
168
|
// Try to serve index.html from the directory
|
|
151
169
|
const indexPath = path.join(filePath, 'index.html');
|
|
152
170
|
if (existsSync(indexPath)) {
|
|
153
|
-
return this.serveFile(indexPath, res
|
|
171
|
+
return this.serveFile(indexPath, res);
|
|
154
172
|
} else {
|
|
155
173
|
res.writeHead(404);
|
|
156
174
|
res.end('404 Not Found');
|
|
@@ -159,56 +177,43 @@ class DevServer {
|
|
|
159
177
|
}
|
|
160
178
|
|
|
161
179
|
// Serve the file
|
|
162
|
-
this.serveFile(filePath, res
|
|
180
|
+
this.serveFile(filePath, res);
|
|
163
181
|
}
|
|
164
182
|
|
|
165
|
-
serveFile(filePath, res
|
|
183
|
+
serveFile(filePath, res) {
|
|
166
184
|
const ext = path.extname(filePath);
|
|
167
|
-
const contentType =
|
|
185
|
+
const contentType = getContentType(ext);
|
|
168
186
|
|
|
169
187
|
try {
|
|
170
188
|
let content = fs.readFileSync(filePath);
|
|
171
189
|
|
|
172
|
-
// Inject client script into HTML files
|
|
173
|
-
if (ext === '.html'
|
|
190
|
+
// Inject client script into HTML files
|
|
191
|
+
if (ext === '.html') {
|
|
174
192
|
content = content.toString();
|
|
175
193
|
// Inject before </body> or </html> or at the end
|
|
176
194
|
if (content.includes('</body>')) {
|
|
177
|
-
content = content.replace('</body>',
|
|
195
|
+
content = content.replace('</body>', this.clientScript + '</body>');
|
|
178
196
|
} else if (content.includes('</html>')) {
|
|
179
|
-
content = content.replace('</html>',
|
|
197
|
+
content = content.replace('</html>', this.clientScript + '</html>');
|
|
180
198
|
} else {
|
|
181
|
-
content = content +
|
|
199
|
+
content = content + this.clientScript;
|
|
182
200
|
}
|
|
183
201
|
}
|
|
184
202
|
|
|
185
|
-
|
|
203
|
+
const headers = { 'Content-Type': contentType };
|
|
204
|
+
if (ext === '.md' || ext === '.txt') {
|
|
205
|
+
headers['Content-Disposition'] = 'inline';
|
|
206
|
+
}
|
|
207
|
+
res.writeHead(200, headers);
|
|
186
208
|
res.end(content);
|
|
187
209
|
} catch (err) {
|
|
188
|
-
|
|
210
|
+
this.logger.error('Error serving file:', err);
|
|
189
211
|
res.writeHead(500);
|
|
190
212
|
res.end('Internal Server Error');
|
|
191
213
|
}
|
|
192
214
|
}
|
|
193
215
|
|
|
194
|
-
getContentType(ext) {
|
|
195
|
-
const types = {
|
|
196
|
-
'.html': 'text/html',
|
|
197
|
-
'.css': 'text/css',
|
|
198
|
-
'.js': 'application/javascript',
|
|
199
|
-
'.json': 'application/json',
|
|
200
|
-
'.png': 'image/png',
|
|
201
|
-
'.jpg': 'image/jpeg',
|
|
202
|
-
'.gif': 'image/gif',
|
|
203
|
-
'.svg': 'image/svg+xml',
|
|
204
|
-
'.ico': 'image/x-icon'
|
|
205
|
-
};
|
|
206
|
-
return types[ext] || 'application/octet-stream';
|
|
207
|
-
}
|
|
208
|
-
|
|
209
216
|
reloadAll() {
|
|
210
|
-
console.log('š¤ Sending reload message to', this.clients.size, 'clients');
|
|
211
|
-
|
|
212
217
|
// Send a simple reload command to all clients
|
|
213
218
|
const message = JSON.stringify({
|
|
214
219
|
type: 'reload-current'
|
|
@@ -221,63 +226,35 @@ class DevServer {
|
|
|
221
226
|
sentCount++;
|
|
222
227
|
}
|
|
223
228
|
});
|
|
224
|
-
|
|
225
|
-
console.log('ā
Reload message sent to', sentCount, 'clients');
|
|
229
|
+
this.logger.log(`Reloaded ${sentCount} client(s)`);
|
|
226
230
|
}
|
|
227
231
|
|
|
228
232
|
close() {
|
|
229
|
-
this.wss.close();
|
|
230
|
-
this.httpServer.close();
|
|
233
|
+
if (this.wss) this.wss.close();
|
|
234
|
+
if (this.httpServer) this.httpServer.close();
|
|
231
235
|
}
|
|
232
236
|
}
|
|
233
237
|
|
|
234
238
|
// File watcher setup
|
|
235
|
-
const setupWatcher = (directory, options, server,
|
|
239
|
+
const setupWatcher = (directory, options, server, logger) => {
|
|
236
240
|
let debounceTimer = null;
|
|
237
|
-
|
|
241
|
+
const outputRootDir = path.resolve(options.rootDir, options.outputPath || '_site');
|
|
238
242
|
|
|
239
243
|
const processChanges = async () => {
|
|
240
|
-
|
|
241
|
-
pendingFiles.clear();
|
|
242
|
-
|
|
243
|
-
console.log('Rebuilding site...');
|
|
244
|
+
logger.log('Rebuilding site...');
|
|
244
245
|
try {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
functions: config.functions || options.functions || {}
|
|
252
|
-
};
|
|
253
|
-
|
|
254
|
-
await buildSite({ ...currentOptions, quiet: true });
|
|
255
|
-
console.log('Rebuild complete');
|
|
246
|
+
await buildSite({
|
|
247
|
+
rootDir: options.rootDir,
|
|
248
|
+
outputPath: options.outputPath,
|
|
249
|
+
quiet: true
|
|
250
|
+
});
|
|
251
|
+
logger.log('Rebuild complete');
|
|
256
252
|
|
|
257
253
|
// Just reload all clients - they'll reload their current page
|
|
258
|
-
console.log('š Reloading all connected clients');
|
|
259
254
|
server.reloadAll();
|
|
260
255
|
|
|
261
|
-
// If screenshots are enabled and pages were changed, capture screenshots
|
|
262
|
-
const pageFiles = files.filter(file =>
|
|
263
|
-
(file.includes('pages/') || file.startsWith('pages/')) &&
|
|
264
|
-
(file.endsWith('.md') || file.endsWith('.yaml') || file.endsWith('.yml'))
|
|
265
|
-
);
|
|
266
|
-
if (screenshotCapture && pageFiles.length > 0) {
|
|
267
|
-
// Wait a bit for the server to be ready with new content
|
|
268
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
269
|
-
|
|
270
|
-
console.log('šø Capturing screenshots for changed pages...');
|
|
271
|
-
// Capture screenshots for changed pages
|
|
272
|
-
for (const file of pageFiles) {
|
|
273
|
-
// The file is already in the format "pages/creator/about.yaml"
|
|
274
|
-
console.log(`šø Capturing screenshot for: ${file}`);
|
|
275
|
-
await screenshotCapture.capturePageScreenshot(file);
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
256
|
} catch (error) {
|
|
280
|
-
|
|
257
|
+
logger.error('Error during rebuild:', error);
|
|
281
258
|
}
|
|
282
259
|
};
|
|
283
260
|
|
|
@@ -291,29 +268,12 @@ const setupWatcher = (directory, options, server, screenshotCapture) => {
|
|
|
291
268
|
return;
|
|
292
269
|
}
|
|
293
270
|
|
|
294
|
-
|
|
295
|
-
if (
|
|
271
|
+
const changedPath = path.resolve(directory, filename);
|
|
272
|
+
if (changedPath === outputRootDir || changedPath.startsWith(outputRootDir + path.sep)) {
|
|
296
273
|
return;
|
|
297
274
|
}
|
|
298
275
|
|
|
299
|
-
|
|
300
|
-
const isStaticDir = directory.endsWith('/static') || directory.includes('/static/');
|
|
301
|
-
if (isStaticDir) {
|
|
302
|
-
const ext = path.extname(filename).toLowerCase();
|
|
303
|
-
const binaryExts = ['.png', '.jpg', '.jpeg', '.gif', '.ico', '.pdf', '.zip', '.woff', '.woff2', '.ttf', '.eot'];
|
|
304
|
-
|
|
305
|
-
if (binaryExts.includes(ext)) {
|
|
306
|
-
// For binary files in static, just copy them without full rebuild
|
|
307
|
-
console.log(`š Static file changed: ${directory}/${filename} (skipping rebuild)`);
|
|
308
|
-
return;
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
console.log(`Detected ${event} in ${filename}`);
|
|
313
|
-
|
|
314
|
-
// Add to pending files for rebuild
|
|
315
|
-
const fullPath = path.join(directory, filename);
|
|
316
|
-
pendingFiles.add(fullPath);
|
|
276
|
+
logger.log(`Detected ${event} in ${filename}`);
|
|
317
277
|
|
|
318
278
|
if (debounceTimer) {
|
|
319
279
|
clearTimeout(debounceTimer);
|
|
@@ -325,82 +285,96 @@ const setupWatcher = (directory, options, server, screenshotCapture) => {
|
|
|
325
285
|
);
|
|
326
286
|
};
|
|
327
287
|
|
|
288
|
+
const setupConfigWatcher = (rootDir, options, server) => {
|
|
289
|
+
let debounceTimer = null;
|
|
290
|
+
const logger = createLogger(options.quiet);
|
|
291
|
+
|
|
292
|
+
watch(rootDir, { recursive: false }, async (event, filename) => {
|
|
293
|
+
if (!filename) {
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const normalized = String(filename).replace(/\\/g, '/');
|
|
298
|
+
const baseName = path.basename(normalized);
|
|
299
|
+
if (baseName !== 'sites.config.yaml' && baseName !== 'sites.config.yml') {
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
logger.log(`Detected ${event} in ${baseName}`);
|
|
304
|
+
|
|
305
|
+
if (debounceTimer) {
|
|
306
|
+
clearTimeout(debounceTimer);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
debounceTimer = setTimeout(async () => {
|
|
310
|
+
logger.log('Rebuilding site...');
|
|
311
|
+
try {
|
|
312
|
+
await buildSite({
|
|
313
|
+
rootDir: options.rootDir,
|
|
314
|
+
outputPath: options.outputPath,
|
|
315
|
+
quiet: true
|
|
316
|
+
});
|
|
317
|
+
logger.log('Rebuild complete');
|
|
318
|
+
server.reloadAll();
|
|
319
|
+
} catch (error) {
|
|
320
|
+
logger.error('Error during rebuild:', error);
|
|
321
|
+
}
|
|
322
|
+
}, 10);
|
|
323
|
+
});
|
|
324
|
+
};
|
|
325
|
+
|
|
328
326
|
// Main watch function
|
|
329
327
|
const watchSite = async (options = {}) => {
|
|
330
328
|
const {
|
|
331
329
|
port = 3001,
|
|
332
330
|
rootDir = process.cwd(),
|
|
333
|
-
|
|
331
|
+
outputPath = '_site',
|
|
332
|
+
quiet = false,
|
|
333
|
+
reloadMode = 'body'
|
|
334
334
|
} = options;
|
|
335
|
+
const normalizedReloadMode = String(reloadMode).toLowerCase();
|
|
336
|
+
if (!RELOAD_MODES.has(normalizedReloadMode)) {
|
|
337
|
+
throw new Error(`Invalid reload mode "${reloadMode}". Allowed values: body, full.`);
|
|
338
|
+
}
|
|
339
|
+
const logger = createLogger(quiet);
|
|
335
340
|
|
|
336
341
|
// Load config file
|
|
337
|
-
|
|
338
|
-
console.log(`š rootDir parameter: ${rootDir}`);
|
|
339
|
-
const config = await loadSiteConfig(rootDir, false);
|
|
340
|
-
|
|
341
|
-
if (Object.keys(config).length > 0) {
|
|
342
|
-
console.log('ā
Loaded sites.config.js');
|
|
343
|
-
if (config.md) {
|
|
344
|
-
console.log('ā
Custom md function found');
|
|
345
|
-
} else {
|
|
346
|
-
console.log('ā¹ļø No custom md function in config');
|
|
347
|
-
}
|
|
348
|
-
if (config.functions) {
|
|
349
|
-
console.log(`ā
Found ${Object.keys(config.functions).length} custom function(s)`);
|
|
350
|
-
}
|
|
351
|
-
} else {
|
|
352
|
-
console.log('ā¹ļø No sites.config.js found, using defaults');
|
|
353
|
-
}
|
|
342
|
+
await loadSiteConfig(rootDir, true, true);
|
|
354
343
|
|
|
355
344
|
// Do initial build with config
|
|
356
|
-
|
|
357
|
-
await buildSite({
|
|
358
|
-
|
|
359
|
-
md: config.md,
|
|
360
|
-
functions: config.functions || {}
|
|
361
|
-
});
|
|
362
|
-
console.log('Initial build complete');
|
|
345
|
+
logger.log('Starting initial build...');
|
|
346
|
+
await buildSite({ rootDir, outputPath, quiet: true });
|
|
347
|
+
logger.log('Initial build complete');
|
|
363
348
|
|
|
364
349
|
// Start custom dev server
|
|
365
|
-
const server = new DevServer(port);
|
|
350
|
+
const server = new DevServer(port, path.resolve(rootDir, outputPath), logger, normalizedReloadMode);
|
|
366
351
|
server.start();
|
|
367
352
|
|
|
368
|
-
// Initialize screenshot capture if enabled
|
|
369
|
-
let screenshotCapture = null;
|
|
370
|
-
if (screenshots) {
|
|
371
|
-
console.log('\nšø Screenshot capture enabled');
|
|
372
|
-
screenshotCapture = await createScreenshotCapture(port);
|
|
373
|
-
}
|
|
374
|
-
|
|
375
353
|
// Watch all relevant directories
|
|
376
|
-
const dirsToWatch = ['data', 'templates', 'partials', 'pages'];
|
|
354
|
+
const dirsToWatch = ['data', 'templates', 'partials', 'pages', 'static'];
|
|
377
355
|
|
|
378
356
|
dirsToWatch.forEach(dir => {
|
|
379
357
|
const dirPath = path.join(rootDir, dir);
|
|
380
358
|
if (existsSync(dirPath)) {
|
|
381
|
-
|
|
359
|
+
logger.log(`Watching: ${dir}/`);
|
|
382
360
|
setupWatcher(dirPath, {
|
|
383
361
|
rootDir,
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
}, server, screenshotCapture);
|
|
362
|
+
outputPath
|
|
363
|
+
}, server, logger);
|
|
387
364
|
}
|
|
388
365
|
});
|
|
389
366
|
|
|
367
|
+
logger.log('Watching: sites.config.yaml');
|
|
368
|
+
setupConfigWatcher(rootDir, { rootDir, outputPath, quiet }, server);
|
|
369
|
+
|
|
390
370
|
// Handle process termination
|
|
391
371
|
process.on('SIGINT', async () => {
|
|
392
|
-
|
|
393
|
-
if (screenshotCapture) {
|
|
394
|
-
await screenshotCapture.close();
|
|
395
|
-
}
|
|
372
|
+
logger.log('\nShutting down server...');
|
|
396
373
|
server.close();
|
|
397
374
|
process.exit();
|
|
398
375
|
});
|
|
399
376
|
|
|
400
377
|
process.on('SIGTERM', async () => {
|
|
401
|
-
if (screenshotCapture) {
|
|
402
|
-
await screenshotCapture.close();
|
|
403
|
-
}
|
|
404
378
|
server.close();
|
|
405
379
|
process.exit();
|
|
406
380
|
});
|