Skip to content

Defer off-screen Query Loop blocks to a viewport placeholder#27

Draft
roborourke wants to merge 1 commit into
mainfrom
claude/query-loop-viewport-placeholder-dh2yld
Draft

Defer off-screen Query Loop blocks to a viewport placeholder#27
roborourke wants to merge 1 commit into
mainfrom
claude/query-loop-viewport-placeholder-dh2yld

Conversation

@roborourke

Copy link
Copy Markdown
Collaborator

Summary

An alternative approach to making pages with many Query Loop blocks more performant in the editor.

Rendering a Query Loop's edit component mounts the core block, which immediately fires a REST request to fetch its posts for the preview. On a page with lots of query loops, every one of those requests is dispatched up front on editor load — slow, and it can hammer the server.

This adds a withViewportPlaceholder HOC that replaces an off-screen Query Loop with a cheap placeholder that issues no requests. The real block is only mounted once it scrolls near the viewport, spreading the API requests out as the user scrolls rather than firing them all at load.

How it works

  • withViewportPlaceholder wraps core/query's editor.BlockEdit. It is registered last, so it is the outermost HOC — while the placeholder is shown, none of the plugin's other core/query enhancements (nor the core block itself) are mounted.
  • QueryLoopPlaceholder renders a <Placeholder> + <Spinner> and attaches an IntersectionObserver. The observer is constructed from the target node's own ownerDocument.defaultView, so it uses the correct viewport whether or not the editor canvas is iframed (site editor / block-themed post editor). A 300px rootMargin preloads a block just before it comes on screen. If IntersectionObserver is unavailable, the block renders immediately as a safe fallback.
  • Immediate render on interaction: selecting the block (e.g. right after inserting it) or selecting one of its inner blocks via the List View renders it immediately, so it never gets stuck as an unmountable placeholder.
  • Latching: once a block has been rendered it stays rendered, so scrolling away does not discard edits or trigger a refetch.

Changes

  • src/index.js — new QueryLoopPlaceholder component and withViewportPlaceholder HOC + filter registration.
  • src/index.scss — placeholder styling (reserves min-height so the block is observable and the layout doesn't jump on swap-in).
  • tests/e2e/viewport-placeholder.spec.js — e2e coverage: off-screen loops render placeholders and load on scroll; a selected loop renders immediately.
  • CLAUDE.md — documents the new lazy-rendering behavior.

Testing

  • npm run build — compiles cleanly.
  • npm run lint:js / npm run lint:css — clean.
  • E2E spec added but not run in this environment (no Docker/wp-env available here).

🤖 Generated with Claude Code


Generated by Claude Code

Rendering a Query Loop's edit component mounts the core block, which
immediately fires a REST request to fetch posts for the preview. On a
page with many query loops, every one of those requests is dispatched up
front on editor load.

Add a withViewportPlaceholder HOC (registered last, so it wraps the
plugin's other core/query enhancements) that replaces an off-screen
Query Loop with a cheap placeholder issuing no requests. An
IntersectionObserver — built from the target node's own defaultView so
it works whether or not the canvas is iframed — swaps in the real block
once it nears the viewport (300px rootMargin preload). Selecting the
block or one of its inner blocks renders it immediately, and once
rendered a block stays rendered so scrolling away neither discards edits
nor refetches.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EAvqR2G3Q3aJkTtePzmLg7
@github-actions

Copy link
Copy Markdown

Playwright test results

passed  22 passed

Details

stats  22 tests across 7 suites
duration  1 minute, 11 seconds
commit  0f34880

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants