Skip to content

Commit 7033e23

Browse files
fix(admin): lazy-load Media Library thumbnails
Media Library page fetched 100 items on first load and rendered every thumbnail eagerly, firing ~100 concurrent resize requests through the Astro image endpoint on mount. Adds loading="lazy" to all thumbnail <img> tags and trims the initial page size to 40. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
1 parent 932f4ba commit 7033e23

4 files changed

Lines changed: 25 additions & 1 deletion

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"emdash": patch
3+
---
4+
5+
Fixes slow load and scroll on the Media Library admin page. Thumbnails now use native `loading="lazy"` so the browser only fetches images as they scroll into view, instead of firing every visible page's worth of resize requests on mount. The initial page size is also reduced from 100 to 40 items.

packages/admin/src/components/MediaLibrary.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,7 @@ function MediaGridItem({ item, selected, onClick }: MediaGridItemProps) {
585585
<img
586586
src={getMediaThumbnailUrl(item.url, item.mimeType, MEDIA_THUMBNAIL_WIDTH)}
587587
alt={item.alt || item.filename}
588+
loading="lazy"
588589
className="h-full w-full object-cover"
589590
onError={(e) => fallbackToOriginalThumbnail(e.currentTarget, item.url)}
590591
/>
@@ -636,6 +637,7 @@ function ProviderGridItem({ item, selected, onClick, onDimensionsLoaded }: Provi
636637
<img
637638
src={item.previewUrl}
638639
alt={item.alt || item.filename}
640+
loading="lazy"
639641
className="h-full w-full object-cover"
640642
onLoad={handleImageLoad}
641643
/>
@@ -679,6 +681,7 @@ function MediaListItem({ item, selected, onClick }: MediaListItemProps) {
679681
<img
680682
src={getMediaThumbnailUrl(item.url, item.mimeType, 80)}
681683
alt={item.alt || item.filename}
684+
loading="lazy"
682685
className="h-full w-full object-cover"
683686
onError={(e) => fallbackToOriginalThumbnail(e.currentTarget, item.url)}
684687
/>
@@ -734,6 +737,7 @@ function ProviderListItem({ item, selected, onClick, onDimensionsLoaded }: Provi
734737
<img
735738
src={item.previewUrl}
736739
alt={item.alt || item.filename}
740+
loading="lazy"
737741
className="h-full w-full object-cover"
738742
onLoad={handleImageLoad}
739743
/>

packages/admin/src/router.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1116,7 +1116,7 @@ function MediaPage() {
11161116
queryFn: ({ pageParam }) =>
11171117
fetchMediaList({
11181118
cursor: pageParam,
1119-
limit: 100,
1119+
limit: 40,
11201120
search: search || undefined,
11211121
mimeType: mimeFilter,
11221122
}),

packages/admin/tests/components/MediaLibrary.test.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,14 @@ describe("MediaLibrary", () => {
9090
await expect.element(img).toBeInTheDocument();
9191
await expect.element(img).toHaveAttribute("src", "https://example.com/photo.jpg");
9292
});
93+
94+
it("grid thumbnails are natively lazy-loaded", async () => {
95+
// A library page can hold up to 100 items; without `loading="lazy"` the
96+
// browser fetches every thumbnail on mount instead of only the visible ones.
97+
const items = [makeMediaItem({ id: "1", filename: "pic.jpg", mimeType: "image/jpeg" })];
98+
const screen = await renderLibrary({ items });
99+
await expect.element(screen.getByAltText("pic.jpg")).toHaveAttribute("loading", "lazy");
100+
});
93101
});
94102

95103
describe("view mode toggle", () => {
@@ -174,6 +182,13 @@ describe("MediaLibrary", () => {
174182
await expect.element(screen.getByText("application/pdf")).toBeInTheDocument();
175183
await expect.element(screen.getByText("1 MB")).toBeInTheDocument();
176184
});
185+
186+
it("list view thumbnails are natively lazy-loaded", async () => {
187+
const items = [makeMediaItem({ id: "1", filename: "pic.jpg", mimeType: "image/jpeg" })];
188+
const screen = await renderLibrary({ items });
189+
await screen.getByRole("button", { name: "List view" }).click();
190+
await expect.element(screen.getByAltText("pic.jpg")).toHaveAttribute("loading", "lazy");
191+
});
177192
});
178193

179194
describe("header", () => {

0 commit comments

Comments
 (0)