Speed up the app, run production build, remove chunk ink, start App.jsx split

Performance:
- Lazy-load pages, docx, and mammoth (initial JS 1,298 KB -> ~290 KB)
- Gzip responses and cache hashed assets for a year
- Memoize DrawCanvas strokes so ink isn't redrawn on every render
- Precompute whole-Bible search index and defer the query while typing
- Reload once if a lazy chunk is missing after a deploy

Deployment:
- setup.sh builds and runs one production server on APP_PORT (default
  5173); --dev keeps the old Vite dev setup
- Session cookie uses secure: 'auto' so login works behind any proxy

Chunk editor:
- Remove the Draw layout, Ink Notes panel, and ink in HTML export
  (existing inkStrokes data is left in saved projects)

Refactor:
- Move module-level helpers out of App.jsx into src/utils/*
- Extract Bible reader state and logic into hooks/useBibleReader

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Opus 5.5 committed 2026-09-22 14:34:13 -04:00
1 parent 00932dee4a
commit ade7f1af6f
20 files changed
+1314 -1252

No files matched your search

+46
View File
@@ -0,0 +1,46 @@
// IndexedDB cache for the whole-Bible search index.
const BIBLE_IDB_NAME = 'study-app-bible-index';
const BIBLE_IDB_STORE = 'bible-index';
export const BIBLE_IDB_TTL = 7 * 24 * 60 * 60 * 1000; // 7 days
function openBibleIndexDB() {
return new Promise((resolve, reject) => {
const req = indexedDB.open(BIBLE_IDB_NAME, 1);
req.onupgradeneeded = (e) => {
const db = e.target.result;
if (!db.objectStoreNames.contains(BIBLE_IDB_STORE)) {
db.createObjectStore(BIBLE_IDB_STORE, { keyPath: 'id' });
}
};
req.onsuccess = (e) => resolve(e.target.result);
req.onerror = () => reject(req.error);
});
}
export async function getBibleIndexFromIDB(translation) {
try {
const db = await openBibleIndexDB();
return new Promise((resolve, reject) => {
const tx = db.transaction(BIBLE_IDB_STORE, 'readonly');
const req = tx.objectStore(BIBLE_IDB_STORE).get(translation);
req.onsuccess = () => resolve(req.result ?? null);
req.onerror = () => reject(req.error);
});
} catch {
return null;
}
}
export async function saveBibleIndexToIDB(translation, flat) {
try {
const db = await openBibleIndexDB();
await new Promise((resolve, reject) => {
const tx = db.transaction(BIBLE_IDB_STORE, 'readwrite');
const req = tx.objectStore(BIBLE_IDB_STORE).put({ id: translation, flat, cachedAt: Date.now() });
req.onsuccess = () => resolve();
req.onerror = () => reject(req.error);
});
} catch {
// Non-fatal; in-memory cache still works for this session
}
}