Skip to content

fix(admin): load resized thumbnails in media library and picker (#1488)#1507

Merged
ascorbic merged 1 commit into
mainfrom
fix/media-library-thumbnail-perf
Jun 16, 2026
Merged

fix(admin): load resized thumbnails in media library and picker (#1488)#1507
ascorbic merged 1 commit into
mainfrom
fix/media-library-thumbnail-perf

Conversation

@ascorbic

@ascorbic ascorbic commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

What does this PR do?

The media library, library list, and the media picker modal loaded every grid item's full-size original through the media proxy (/_emdash/api/media/file/{key}). On large libraries this made opening the library and searching for older items wait on full-resolution downloads (the 1 min+ in the issue). Media search itself is already server-side (since #1227); the bottleneck was the thumbnails, not the query.

This routes same-origin raster images through Astro's runtime image endpoint (/_image) to request a small resized rendition for the grid/list instead of the original. EmDash already wires this pipeline (the integration registers an image.remotePatterns entry scoped to the media route), so no new route or serving path is added.

Behavior by environment:

  • Node (sharp) and Cloudflare default (@astrojs/cloudflare v13 cloudflare-binding, auto-provisioned IMAGES binding): the grid gets lightweight thumbnails.
  • No runtime image service (a passthrough config) or the endpoint rejects the request (e.g. a site with no build-time siteUrl, so the production remote pattern isn't registered): /_image serves the original, and an onError handler falls back to the original URL. Nothing renders worse than before.

Details:

  • New getMediaThumbnailUrl() builds the /_image URL for same-origin raster images and passes through non-images (an icon renders), SVGs (vector), and external/provider URLs (already remote renditions).
  • In the picker, items whose dimensions are unknown still load the original, so the existing onLoad dimension backfill reads true naturalWidth/naturalHeight rather than the thumbnail's.
  • Detail-panel full previews and the selected-item value are untouched (still full-size).

Because the thumbnails ride Astro's /_image pipeline, any future improvement to same-origin image transforms (for example making them work behind Cloudflare Access) benefits these thumbnails with no further change here.

Closes #1488

Type of change

  • Bug fix
  • Feature (requires maintainer-approved Discussion)
  • Refactor (no behavior change)
  • Translation
  • Documentation
  • Performance improvement
  • Tests
  • Chore (dependencies, CI, tooling)

Checklist

  • I have read CONTRIBUTING.md
  • pnpm typecheck passes
  • pnpm lint passes
  • pnpm test passes (or targeted tests for my change)
  • pnpm format has been run
  • I have added/updated tests for my changes (if applicable)
  • User-visible strings in the admin UI are wrapped for translation (if applicable) — n/a, no new user-visible strings
  • I have added a changeset (if this PR changes a published package)
  • New features link to an approved Discussion — n/a, bug fix

AI-generated code disclosure

  • This PR includes AI-generated code — model/tool: Claude Opus 4.8 (opencode)

Screenshots / test output

✓ tests/lib/media-thumbnail.test.ts (7 tests)
✓ tests/lib/media-search.test.ts (4 tests)
✓ tests/components/MediaLibrary.test.tsx (15 tests)

pnpm lint:json 0 diagnostics, pnpm typecheck clean, pnpm format run.

The media library, library list, and picker modal loaded every grid item's
full-size original through the media proxy, so opening the library and
searching for older items waited on full-resolution downloads (1 min+ on
large libraries).

Route same-origin raster images through Astro's runtime image endpoint
(/_image) to request a small resized rendition instead. Where no runtime
image service transforms (passthrough config, or the endpoint rejects the
request) the original is served as before, so nothing renders worse. Items
with unknown dimensions still load the original so onLoad can backfill true
dimensions rather than the thumbnail's.
@changeset-bot

changeset-bot Bot commented Jun 16, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 6a94cb6

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 14 packages
Name Type
@emdash-cms/admin Patch
emdash Patch
@emdash-cms/cloudflare Patch
@emdash-cms/sandbox-workerd Patch
@emdash-cms/fixture-perf-site Patch
@emdash-cms/perf-demo-site Patch
@emdash-cms/cache-demo-site Patch
@emdash-cms/auth Patch
@emdash-cms/blocks Patch
@emdash-cms/gutenberg-to-portable-text Patch
@emdash-cms/x402 Patch
create-emdash Patch
@emdash-cms/auth-atproto Patch
@emdash-cms/plugin-embeds Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions Bot added review/needs-review No maintainer or bot review yet area/admin size/M labels Jun 16, 2026
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
docs 6a94cb6 Jun 16 2026, 02:39 PM

@pkg-pr-new

pkg-pr-new Bot commented Jun 16, 2026

Copy link
Copy Markdown

Open in StackBlitz

@emdash-cms/admin

npm i https://pkg.pr.new/@emdash-cms/admin@1507

@emdash-cms/auth

npm i https://pkg.pr.new/@emdash-cms/auth@1507

@emdash-cms/auth-atproto

npm i https://pkg.pr.new/@emdash-cms/auth-atproto@1507

@emdash-cms/blocks

npm i https://pkg.pr.new/@emdash-cms/blocks@1507

@emdash-cms/cloudflare

npm i https://pkg.pr.new/@emdash-cms/cloudflare@1507

@emdash-cms/contentful-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/contentful-to-portable-text@1507

emdash

npm i https://pkg.pr.new/emdash@1507

create-emdash

npm i https://pkg.pr.new/create-emdash@1507

@emdash-cms/gutenberg-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/gutenberg-to-portable-text@1507

@emdash-cms/plugin-cli

npm i https://pkg.pr.new/@emdash-cms/plugin-cli@1507

@emdash-cms/plugin-types

npm i https://pkg.pr.new/@emdash-cms/plugin-types@1507

@emdash-cms/registry-client

npm i https://pkg.pr.new/@emdash-cms/registry-client@1507

@emdash-cms/registry-lexicons

npm i https://pkg.pr.new/@emdash-cms/registry-lexicons@1507

@emdash-cms/sandbox-workerd

npm i https://pkg.pr.new/@emdash-cms/sandbox-workerd@1507

@emdash-cms/x402

npm i https://pkg.pr.new/@emdash-cms/x402@1507

@emdash-cms/plugin-ai-moderation

npm i https://pkg.pr.new/@emdash-cms/plugin-ai-moderation@1507

@emdash-cms/plugin-atproto

npm i https://pkg.pr.new/@emdash-cms/plugin-atproto@1507

@emdash-cms/plugin-audit-log

npm i https://pkg.pr.new/@emdash-cms/plugin-audit-log@1507

@emdash-cms/plugin-color

npm i https://pkg.pr.new/@emdash-cms/plugin-color@1507

@emdash-cms/plugin-embeds

npm i https://pkg.pr.new/@emdash-cms/plugin-embeds@1507

@emdash-cms/plugin-field-kit

npm i https://pkg.pr.new/@emdash-cms/plugin-field-kit@1507

@emdash-cms/plugin-forms

npm i https://pkg.pr.new/@emdash-cms/plugin-forms@1507

@emdash-cms/plugin-webhook-notifier

npm i https://pkg.pr.new/@emdash-cms/plugin-webhook-notifier@1507

commit: 6a94cb6

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
emdash-playground 6a94cb6 Jun 16 2026, 02:40 PM

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
emdash-demo-cache 6a94cb6 Jun 16 2026, 02:40 PM

@ascorbic ascorbic merged commit 6c1fe5c into main Jun 16, 2026
46 of 47 checks passed
@ascorbic ascorbic deleted the fix/media-library-thumbnail-perf branch June 16, 2026 14:48
@emdashbot emdashbot Bot mentioned this pull request Jun 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug - Media Library - Search fails when element not in first loaded set of entries

1 participant