mirror of
https://github.com/got-feedBack/feedBack.git
synced 2026-07-20 20:01:21 +00:00
* perf(folder_library): render only the songs on screen (#965) A song list rendered EVERY song it held. On a flat 50,944-song library that is one <div> with 50,938 children and ~1,300,000 DOM nodes — ~4.2 GB of renderer RSS, for a screen the user may not even be looking at (it was built while the visible screen was v3-home). It is not just this plugin's problem. A million-node document poisons unrelated code: any `document.querySelector` that MISSES has to walk the whole tree before returning null. That is exactly how song_preview's per-frame menu check ended up consuming ~50% of the renderer and dropping the app to 2.7 fps (feedBack-plugin-song-preview#7 fixes the per-frame walk; this fixes the tree it was walking). So render only what is on screen. Rows are uniform height (grid cards uniform size), so the window is pure arithmetic — no per-row observers. Off-window songs are represented by padding ON THE LIST rather than spacer elements: a spacer div would become a grid ITEM in grid view and shift the columns, whereas padding behaves identically in both layouts. Lists at or below VIRTUAL_MIN (200) render in full exactly as before, so normal folders are untouched. Two ordering fixes this forced, both real bugs waiting to happen: - Both expand handlers populated the list BEFORE showing it. A windowed list measures a real row and the scroller viewport, and both are zero under display:none. Show first, then populate. - _render() now tears down the previous render's scroll listeners. Without it they survive against detached nodes and leak on every re-render. Verified in real Chromium over CDP with 50,000 rows — the DOM glue, not just the maths: at top rendered= 25 rows scrollHeight=2,200,000px [0..24] scroll 500k rendered= 31 rows scrollHeight=2,200,000px [11357..11387] scroll 1,100k rendered= 31 rows scrollHeight=2,200,000px [24994..25024] scroll to end rendered= 25 rows scrollHeight=2,200,000px [49975..49999] 25-31 rows in the DOM instead of 50,000; scroll height exact and constant (the scrollbar stays honest); the last row lands on song 49,999. Tests: _visibleWindow is pure and exposed via __test — top/middle/bottom/past- the-end windows, the grid row-packing case, the padding-plus-rendered-equals- total invariant that keeps the list from changing height as you scroll, and the degenerate zero-height case (a list still display:none) falling back to render-everything rather than to an empty list. eslint clean; full JS suite 1186/1186. * fix(folder_library): re-window on resize and on show/hide (PR #967 review) CodeRabbit caught two real bugs in the first pass. Both are mine. 1. GRID RESIZE. perRow and rows were captured once when the list was filled, but paint() also runs on resize — and resizing changes the grid's column count. The window maths then sliced against the OLD column count: wrong songs on screen, and padding sized for a row count the layout no longer had (so the scrollbar lied). metrics() now recomputes perRow/itemH/rows together on every paint, so the geometry can never disagree with itself. 2. STALE WINDOWS ON SHOW/HIDE. paint() only ran on scroll and resize. Expanding or collapsing any section moves every list below it, and a windowed list's contents are a function of its POSITION — so those lists kept the window from their old position and showed blank padding where songs should be until the user happened to scroll. Both toggles now call _repaintVirtualLists(). Re-opening an already-populated section had the same flaw. Collapsed lists also kept doing layout work on every scroll tick. paint() now bails early when the list is display:none or detached, and forgets its last window so re-showing repaints from scratch instead of short-circuiting on a stale memo. Tests: grid re-window on a column-count change, the padding+rendered=rows invariant at two different perRow values, and a test that PINS THE FAILURE MODE — a mismatched perRow/rows pair must not silently look correct. 12/12. Re-validated the DOM glue in real Chromium with 50k rows (25-31 rows rendered, scroll height exact). eslint clean; JS 1189/1189; pytest 2597 passed. CHANGELOG entry added (also flagged). |
||
|---|---|---|
| .claude/skills | ||
| .github | ||
| .specify | ||
| content/starter | ||
| data/progression | ||
| docs | ||
| lib | ||
| plugins | ||
| scripts | ||
| specs | ||
| static | ||
| tests | ||
| tools | ||
| .dockerignore | ||
| .gitattributes | ||
| .gitignore | ||
| build-proxmox-ct.sh | ||
| CHANGELOG.md | ||
| CLAUDE.md | ||
| CONTRIBUTING.md | ||
| docker-compose.nas.yml | ||
| docker-compose.yml | ||
| Dockerfile | ||
| eslint.config.js | ||
| feedpak-spec-exceptions.yml | ||
| LICENSE | ||
| main.py | ||
| package-lock.json | ||
| package.json | ||
| playwright.config.ts | ||
| pyproject.toml | ||
| requirements-test.txt | ||
| requirements.txt | ||
| server.py | ||
| SUPPORTERS.md | ||
| tailwind.config.js | ||
| TODO.md | ||
| uv.lock | ||
| VERSION | ||