perf(nad): lazyMount helper to defer off-screen viewer construction - #9
Draft
gautierbureau wants to merge 1 commit into
Draft
Conversation
A page that stacks several diagrams constructs them all on load, even the off-screen ones; each NAD costs ~100 ms of synchronous first-paint work, so an N-viewer page pays N× that up front. lazyMount(container, factory) defers the factory until its container is (near) the viewport via an IntersectionObserver, building each viewer only when scrolled into view. On a page showing ~1 of N, initial construction work drops roughly N× and the first visible diagram appears sooner. The factory runs at most once; the returned function cancels a still-pending mount. Falls back to running the factory immediately when IntersectionObserver is unavailable (non-DOM environments), so callers never branch on support. The container must reserve layout space or a zero-height box collapses into the viewport and mounts right away (documented on the helper). This is the outer visibility gate; it stacks with the adaptive-zoom writer's per-zoom element gating (whole-viewer vs per-element deferral, orthogonal). Exported from both entry points. 5 unit tests cover defer/build-once/cancel/ disconnect, sync + async error handling, and the no-observer fallback. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T1fMV9gtgHLBKoSAShYSdA
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context
Layered on the adaptive-zoom SVG-writer branch (PR powsybl#423 upstream, imported here as
integration/nad_create_svg_adaptive_zoom). Last of three complementary performance PRs stacked on that branch.Problem
A page that stacks several diagrams constructs all of them on load, including the off-screen ones. Each NAD costs real synchronous work on the main thread, so an N-viewer page pays ~N× that cost up front before the user can see anything.
Change
Add
lazyMount(container, factory, options?): it defersfactoryuntilcontaineris at (or near, viarootMargin, default200px) the viewport, using anIntersectionObserver. Each viewer is built only when scrolled into view.factoryruns at most once; the returned function cancels a still-pending mount.factoryimmediately whenIntersectionObserveris unavailable (non-DOM environments), so callers never branch on support.factorythat returns a promise (async construction) and routes sync/async errors toonError.min-height); a zero-height box collapses into the viewport and mounts immediately, defeating the purpose.Measured impact
Real headless Chromium, N
case1354pegaseviewers stacked in a one-viewport scroll container, eager (build all on load) vs lazy (IntersectionObserver, build on view) — viabenchmarks/nad-lazy-mount-bench.mjs(PR #11):N / visible(≈2 visible here), so a page showing ~1 of N approaches an N× reduction in initial-load construction work. All N build on demand while scrolling (8/8, 16/16 — correctness confirmed).Relationship to powsybl#423
This is the outer visibility gate — which whole viewers to build. It stacks cleanly with powsybl#423's inner gate — which elements to draw at the current zoom. Orthogonal axes of "don't build what you can't see"; no shared code, mergeable in any order.
Tests / surface
@powsybl/network-viewer-coreand the root package). Purely additive — no existing behaviour changes.Draft, base is the in-progress adaptive-zoom branch.
🤖 Generated with Claude Code