svm0n_datadeck/bench-load.mjs
SVM0N 3b213d0650 SWITCH TO CSV AS MAIN: retire XLSX, drop SheetJS, simplify save path
Plugin is CSV-only. registerExtensions(["csv"]); SheetJS gone; the
_csv_helpers/ mirror collapses to a single canonical CSV. Bundle drops
720 KB → 297 KB (-59%); parse+eval 0.9 ms → 0.5 ms.

Migration plan was empirically validated before any data was touched:
xlsx-to-csv-roundtrip.mjs reads each xlsx, Papa.unparse → Papa.parse,
cell-by-cell compares the result to the source. All 10 checks passed
across books / movies / quotes / dictionary / habit_tracker — proves
the round-trip is lossless including multiline notes, stars, embedded
punctuation, and unicode.

migrate-xlsx-to-csv.mjs is the cutover: writes canonical csv, moves
xlsx → Archive/<name>_pre-csv-migration.xlsx (recoverable), removes
the _csv_helpers/ folder, rewrites data.json fileConfigs keys from
*.xlsx → *.csv so per-file overrides survive.

Code surface:
- main.ts: onLoadFile / doSave / generateMobileFiles / renderAddEntryForm
  all collapsed to the csv-only path; loadXLSX + isXlsx removed.
- mobile dashboards: csv-add and dataviewjs now point at the same
  canonical csv (used to be split because Dataview couldn't read xlsx).
- regenerate-mobile-dashboards.mjs: drops the helper-folder path.
- package.json: xlsx dependency removed (9 transitive packages gone).

Also included in this commit (carried over from the same session):
- mobile toolbar: ⚙ Columns / 📱 Mobile / 💾 Backup collapse into a
  ⋯ overflow menu on screens ≤ 600 px so the toolbar fits on one row.
- mobile compact density: pure-CSS media-query switch for Library
  (2-col compact grid + mobile-md card style), tighter Kanban cards,
  smaller Table cells.

Tests: 88 plugin + 21 mobile-dashboard, all green. Typecheck clean.

Verified manually: open books.csv, edit a note (saves debounce), open
on iPhone (compact library grid, ⋯ menu, csv-add form pre-fills).

Class name XLSXCardView left in place to keep this commit focused on
behavior; rename to CardView is a noted follow-up in handoff.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 07:23:02 +00:00

62 lines
2.8 KiB
JavaScript

/**
* Approximate the cost Obsidian pays when enabling the plugin.
*
* Two numbers worth comparing across a refactor:
*
* Parse — time V8 spends turning the bundle text into bytecode the first
* time it sees it. This is what Obsidian's plugin-enable step pays
* on every launch. Lazy-parsed function bodies (uncalled functions)
* don't count here; they only get parsed on first call.
*
* Eval — time spent executing the bundle's top-level code. For Obsidian
* this is the plugin's `onload()` plus every module's top-level
* initialiser (Chart.js registers default components, etc.). Used
* to be more dramatic when SheetJS was in here too — the
* CSV-only migration retired that ~700 KB lazy chunk.
*
* The bundle uses Obsidian APIs and a few globals, so we stub `require` and
* `module` enough for the file to evaluate without throwing.
*/
import { readFileSync } from "fs";
import vm from "vm";
const path = process.argv[2] ?? "main.js";
const code = readFileSync(path, "utf8");
const sizeKB = (code.length / 1024).toFixed(1);
const RUNS = 5;
// ── Parse only (no execution) ────────────────────────────────────────────────
const parseTimes = [];
for (let i = 0; i < RUNS; i++) {
const t = performance.now();
new vm.Script(code, { filename: path });
parseTimes.push(performance.now() - t);
}
const parseAvg = parseTimes.reduce((a, b) => a + b, 0) / RUNS;
// ── Parse + top-level execute ────────────────────────────────────────────────
// Stub the bits the bundle pokes at module scope. We don't care about correctness
// here, only about reaching the end of top-level evaluation.
const stubObsidian = new Proxy({}, { get: () => class { register() {} addCommand() {} addSettingTab() {} } });
const evalTimes = [];
for (let i = 0; i < RUNS; i++) {
const ctx = vm.createContext({
module: { exports: {} },
exports: {},
require: (id) => (id === "obsidian" ? stubObsidian : {}),
globalThis: {},
process: { env: {} },
setTimeout, clearTimeout, setInterval, clearInterval, console,
});
const t = performance.now();
try { new vm.Script(code, { filename: path }).runInContext(ctx); }
catch { /* downstream throws are fine — we only care about reaching parse + top-level eval */ }
evalTimes.push(performance.now() - t);
}
const evalAvg = evalTimes.reduce((a, b) => a + b, 0) / RUNS;
console.log(`${path}`);
console.log(` Size: ${sizeKB} KB`);
console.log(` Parse only: ${parseAvg.toFixed(1)} ms (avg of ${RUNS})`);
console.log(` Parse+eval: ${evalAvg.toFixed(1)} ms (avg of ${RUNS})`);