« get me outta code hell

client: move search into worker, defer loading - hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src/static/js/search-worker.js
diff options
context:
space:
mode:
author(quasar) nebula <qznebula@protonmail.com>2024-05-02 15:15:55 -0300
committer(quasar) nebula <qznebula@protonmail.com>2024-05-31 12:11:48 -0300
commitf415551fb45174f2618f916fd323fb076adfd7a6 (patch)
tree6a8752ba4a647f635c80dd069357eb944404fd2e /src/static/js/search-worker.js
parent284f32fc0aa6d6aa513961d53dfc091cd09580c2 (diff)
client: move search into worker, defer loading
Diffstat (limited to 'src/static/js/search-worker.js')
-rw-r--r--src/static/js/search-worker.js92
1 files changed, 92 insertions, 0 deletions
diff --git a/src/static/js/search-worker.js b/src/static/js/search-worker.js
new file mode 100644
index 00000000..7932655b
--- /dev/null
+++ b/src/static/js/search-worker.js
@@ -0,0 +1,92 @@
+import {makeSearchIndexes} from '../shared-util/searchSchema.js';
+import {withEntries} from '../shared-util/sugar.js';
+
+import FlexSearch from '../lib/flexsearch/flexsearch.bundle.module.min.js';
+
+let status = null;
+
+onmessage = handleWindowMessage;
+
+postStatus('alive');
+
+const indexes =
+  makeSearchIndexes(FlexSearch);
+
+const searchData =
+  await fetch('/search-data/index.json')
+    .then(resp => resp.json());
+
+// If this fails, it's because an outdated index was cached.
+// TODO: If this fails, try again once with a cache busting url.
+for (const [indexName, indexData] of Object.entries(searchData)) {
+  for (const [key, value] of Object.entries(indexData)) {
+    indexes[indexName].import(key, value);
+  }
+}
+
+postStatus('ready');
+
+function handleWindowMessage(message) {
+  switch (message.data.kind) {
+    case 'action':
+      handleWindowActionMessage(message);
+      break;
+
+    default:
+      console.warn(`Unknown message kind -> to search worker:`, message.data);
+      break;
+  }
+}
+
+async function handleWindowActionMessage(message) {
+  const {id} = message.data;
+
+  if (!id) {
+    console.warn(`Action without id -> to search worker:`, message.data);
+    return;
+  }
+
+  if (status !== 'ready') {
+    return postActionResult(id, 'reject', 'not ready');
+  }
+
+  let value;
+
+  switch (message.data.action) {
+    case 'search':
+      value = await performSearch(message.data.options);
+      break;
+
+    default:
+      console.warn(`Unknown action "${message.data.action}" -> to search worker:`, message.data);
+      return postActionResult(id, 'reject', 'unknown action');
+  }
+
+  await postActionResult(id, 'resolve', value);
+}
+
+function postStatus(newStatus) {
+  status = newStatus;
+  postMessage({
+    kind: 'status',
+    status: newStatus,
+  });
+}
+
+function postActionResult(id, status, value) {
+  postMessage({
+    kind: 'result',
+    id,
+    status,
+    value,
+  });
+}
+
+function performSearch({query, options}) {
+  return (
+    withEntries(indexes, entries => entries
+      .map(([indexName, index]) => [
+        indexName,
+        index.search(query, options),
+      ])));
+}