« get me outta code hell

hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src/write/build-modes/live-dev-server.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/write/build-modes/live-dev-server.js')
-rw-r--r--src/write/build-modes/live-dev-server.js73
1 files changed, 60 insertions, 13 deletions
diff --git a/src/write/build-modes/live-dev-server.js b/src/write/build-modes/live-dev-server.js
index f6eec334..5dece8d0 100644
--- a/src/write/build-modes/live-dev-server.js
+++ b/src/write/build-modes/live-dev-server.js
@@ -1,11 +1,14 @@
 import {spawn} from 'node:child_process';
 import * as http from 'node:http';
 import {open, stat} from 'node:fs/promises';
+import * as os from 'node:os';
 import * as path from 'node:path';
 import {pipeline} from 'node:stream/promises';
 import {inspect as nodeInspect} from 'node:util';
 
-import {ENABLE_COLOR, colors, logInfo, logWarn, progressCallAll} from '#cli';
+import {openAggregate} from '#aggregate';
+import {ENABLE_COLOR, colors, fileIssue, logInfo, logWarn, progressCallAll}
+  from '#cli';
 import {watchContentDependencies} from '#content-dependencies';
 import {quickEvaluate} from '#content-function';
 import * as html from '#html';
@@ -165,21 +168,47 @@ export async function go({
 
   const commonUtilities = {...universalUtilities};
 
+  const pathAggregate = openAggregate({message: `Errors computing page paths`});
+
   let targetSpecPairs = getPageSpecsWithTargets({wikiData});
-  const pages = progressCallAll(`Computing page data & paths for ${targetSpecPairs.length} targets.`,
+  const pages = progressCallAll(`Computing page paths for ${targetSpecPairs.length} targets.`,
     targetSpecPairs.flatMap(({
       pageSpec,
       target,
       targetless,
     }) => () => {
-      if (targetless) {
-        const result = pageSpec.pathsTargetless({wikiData});
-        return Array.isArray(result) ? result : [result];
-      } else {
-        return pageSpec.pathsForTarget(target);
+      try {
+        if (targetless) {
+          const result = pageSpec.pathsTargetless({wikiData});
+          return Array.isArray(result) ? result : [result];
+        } else {
+          return pageSpec.pathsForTarget(target);
+        }
+      } catch (caughtError) {
+        if (targetless) {
+          pathAggregate.push(new Error(
+            `Failed to compute targetless paths for ` +
+            inspect(pageSpec, {compact: true}),
+            {cause: caughtError}));
+        } else {
+          pathAggregate.push(new Error(
+            `Failed to compute paths for ` +
+            inspect(target),
+            {cause: caughtError}));
+        }
+        return [];
       }
     })).flat();
 
+  try {
+    pathAggregate.close();
+  } catch (error) {
+    niceShowAggregate(error);
+    logWarn`Failed to compute page paths for some targets.`;
+    logWarn`This means some pages that normally exist will be 404s.`;
+    fileIssue();
+  }
+
   logInfo`Will be serving a total of ${pages.length} pages.`;
 
   const urlToPageMap = Object.fromEntries(pages
@@ -224,7 +253,7 @@ export async function go({
     let url;
     try {
       url = new URL(request.url, `http://${request.headers.host}`);
-    } catch (error) {
+    } catch {
       response.writeHead(500, contentTypePlain);
       response.end('Failed to parse request URL\n');
       return;
@@ -271,7 +300,7 @@ export async function go({
       let filePath;
       try {
         filePath = path.resolve(localDirectory, decodeURI(safePath.split('/').join(path.sep)));
-      } catch (error) {
+      } catch {
         response.writeHead(404, contentTypePlain);
         response.end(`File not found for: ${safePath}`);
         console.log(`${requestHead} [404] ${pathname}`);
@@ -361,7 +390,11 @@ export async function go({
     // URL to page map expects trailing slash but no leading slash.
     const pathnameKey = pathname.replace(/^\//, '') + (pathname.endsWith('/') ? '' : '/');
 
-    if (!Object.hasOwn(urlToPageMap, pathnameKey)) {
+    const is404 =
+      !Object.hasOwn(urlToPageMap, pathnameKey) ||
+      !(urlToPageMap[pathnameKey].page.condition?.() ?? true);
+
+    if (is404) {
       response.writeHead(404, contentTypePlain);
       response.end(`No page found for: ${pathnameKey}\n`);
       if (loudResponses) console.log(`${requestHead} [404] ${pathname} (no page)`);
@@ -430,7 +463,7 @@ export async function go({
         language,
         pagePath: servePath,
         pagePathStringFromRoot: pathname.replace(/^\//, ''),
-        to,
+        to: page.absoluteLinks ? absoluteTo : to,
       });
 
       const topLevelResult =
@@ -460,7 +493,13 @@ export async function go({
     }
   });
 
-  const address = `http://${host}:${port}/`;
+  const addresses =
+    (host === '0.0.0.0'
+      ? [`http://localhost:${port}/`,
+         `http://${os.hostname()}:${port}/`]
+   : host === '127.0.0.1'
+      ? [`http://localhost:${port}/`]
+      : [`http://${host}:${port}/`]);
 
   server.on('error', error => {
     if (error.code === 'EADDRINUSE') {
@@ -477,7 +516,15 @@ export async function go({
   });
 
   server.on('listening', () => {
-    logInfo`${'All done!'} Listening at: ${address}`;
+    if (addresses.length === 1) {
+      logInfo`${'All done!'} Listening at: ${addresses[0]}`;
+    } else {
+      logInfo`${`All done!`} Listening at:`;
+      for (const address of addresses) {
+        logInfo`- ${address}`;
+      }
+    }
+
     logInfo`Press ^C here (control+C) to stop the server and exit.`;
     if (showTimings && loudResponses) {
       logInfo`Printing all HTTP responses, plus page generation timings.`;