Skip to content

optimization/performance#48

Merged
developStorm merged 69 commits intodevelopStorm:masterfrom
osabl:optimization/performance
Aug 26, 2025
Merged

optimization/performance#48
developStorm merged 69 commits intodevelopStorm:masterfrom
osabl:optimization/performance

Conversation

@osabl
Copy link
Copy Markdown
Contributor

@osabl osabl commented Aug 13, 2025

feat: Virtual scrolling and performance optimization

Visual Review & Performance Test: You can quickly review the visual changes and compare loading/rendering performance by visiting the preview environment.
Open Preview on Netlify

Summary

This branch introduces a virtualized, responsive grid for badge rendering, improves perceived and actual performance (less DOM, faster reflows), refines search and ordering behavior, optimizes image loading, and updates tooling and tests. The overall goal is to make the UI smoother at scale while keeping the codebase more modular and testable.

Changes

New Features

  • Virtualized Badge Grid (Virtual Window):
    • Added virtual-window.js and integrated virtual-scroller (v1.13.1) to render badges in rows on demand.
    • Technical Impact: Dramatically reduces the DOM node count and layout work, enabling smooth scrolling with large datasets.

Improvements

  • Responsive Grid Computation:

    • Added functionality to support the virtual-scroller, as it lacks native Grid Layout support in its DOM version. This was achieved by dynamically computing the number of elements per row based on CSS variables (--grid-width, --grid-gap) and the container's width.
    • The utils.groupIntoRows utility was introduced to group items into rows for the virtual scroller.
    • Technical Impact: This simulated grid layout allowed us to use virtual scrolling and achieve a responsive layout that adapts to screen size changes.
  • Graceful Degradation:

    • To ensure graceful degradation, the original non-virtualized rendering logic and element display method have been preserved within a <noscript> tag. This guarantees the page remains functional and accessible to users with JavaScript disabled.
  • Image Loading Performance and UX:

    • The new icons.js file creates each grid item and:
      • Shows a lightweight loader (Ellipse) placeholder.
      • Fetches badge images, creates object URLs, and caches them in-memory (imageCache).
    • Technical Impact: Provides faster initial paint with graceful progressive loading and avoids redundant network fetches to the shield.io server within a session.
  • Search Module Refactoring:

    • search.js was refactored to work with the new rendering logic via the 'virtual window'.
    • Technical Impact: The decoupled logic improves testability and state management, which is essential for interaction with the new rendering mechanism.
  • Ordering Module Refactor:

    • ordering.js is now initialized with getBadges and onOrderChange callbacks.
    • It exposes sortBadges, allowing external callers to sort any list by the current selection; persists the preferred ordering except when relevance is active.
    • Technical Impact: A more modular and predictable ordering pipeline; simpler integration with search and the virtual window.
  • Copy Button Handling Optimization:

    • copy.js centralizes event handling via delegation on the virtual list container; preserves copy-as Markdown/HTML/Link options.
    • Technical Impact: Less per-element listener overhead.
  • Templating Updates and Loader:

    • index.pug now includes a loader image and updated containers (virtual-list, grid-rows-container) to cooperate with virtualization.
    • Technical Impact: Better perceived loading state and proper DOM anchors for the virtual scroller.
  • Dependency and Tooling Updates:

    • simple-icons upgraded from 15.8.0 to 15.10.0.
    • Added virtual-scroller@1.13.1.
    • jest.config.js adds moduleNameMapper for image imports to support new icons loader behavior in tests.
    • Technical Impact: Keeps the icon set current and ensures tests run smoothly with asset imports.
  • Testing:

    • New tests were written to cover the virtual window's functionality.
    • One e2e test was commented out because its implementation is incompatible with the new rendering method (dynamic rendering via the virtual window).

Notes

  • No breaking API changes are expected for external consumers; internal modules now communicate via injected callbacks and shared utilities.
  • The branch focuses on scalability and UX polish; most changes under “Improvements” re-implement existing behaviors with better performance, readability, and maintainability.

osabl added 30 commits August 4, 2025 19:20
@osabl osabl changed the title Optimization/performance optimization/performance Aug 13, 2025
@osabl osabl mentioned this pull request Aug 13, 2025
@developStorm developStorm requested a review from Copilot August 18, 2025 06:27

This comment was marked as outdated.

@developStorm
Copy link
Copy Markdown
Owner

Thanks a lot for the PR! 🙏

I do have a few concerns:

  • I’m not fully convinced there’s a performance issue here. The page loads fine on my devices, and both Lighthouse and the DevTools performance tab show good scores. All badges already use loading=lazy, and all grid items have content-visibility:auto, which (as I understand it) should prevent unnecessary rendering in modern browsers.
  • I’m a bit wary of introducing a virtual scroller, mainly because of added complexity and compatibility concerns. For example, on iOS Safari the scroller no longer follows the page scroll for me.
  • This repo is technically a fork of the Simple Icons website. One of the original goals was to keep changes to a minimum so syncing with upstream would be easier—though admittedly we’re already pretty out of sync ;(

For those reasons, I’m inclined not to merge this unless I can reliably reproduce the performance issue we’re trying to address. Thanks again for taking the time to put this together - it’s much appreciated!

osabl and others added 6 commits August 18, 2025 10:41
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@osabl
Copy link
Copy Markdown
Contributor Author

osabl commented Aug 18, 2025

Hi, thanks a lot for the thoughtful feedback! 🙏

I did some additional testing and I think I understand why the issue is not reproducible on all devices. Let me share my findings step by step:

1. Performance difference by device/browser

  • On more powerful or newer machines the site loads fine.
  • On mid-range or older devices, the page can completely freeze for 2–3 minutes when opened in Google Chrome (Windows or Android).
  • Interestingly, the issue does not appear in Firefox on desktop, nor in Safari on iOS (and Chrome on iOS works fine too, since it’s Safari under the hood).

2. Cause

  • The main bottleneck seems to be the very large DOM tree (3300+ card elements rendered at once).
  • Even though loading="lazy" and content-visibility: auto help, Chrome still struggles significantly with this DOM size on less powerful hardware.

3. Reproducing the issue

  • Use Google Chrome on Windows or Android with a mid-range device (e.g., my 5-year-old laptop with 16 GB RAM and an i5 CPU).
  • The page loads, but once you start scrolling a little (so that new elements need to render), Chrome can freeze completely for 2–3 minutes.
  • During this time, the entire page is unresponsive.

4. Upstream reference

  • The official simple icons website already moved away from this old approach.
  • They completely rewrote the project (new repo) and introduced lazy loading, so that the browser doesn’t need to render all 3300+ cards at once, which makes sense — users typically don’t need to see all 3300+ icons instantly; most will scroll a bit or just use search.
  • For reference: simple-icons-website issue #244 describes the same performance problem.

So in short:

  • The issue is real but hardware/browser dependent.
  • Chrome on less powerful devices is where it becomes critical.
  • Firefox and Safari users might not notice, which explains why it doesn’t reproduce for everyone.

I completely understand the concerns about complexity and compatibility. I just wanted to clarify the motivation and show that this fix directly targets a real usability problem for Chrome users on mid-range hardware.

Thanks again for taking the time to review this PR! 🙏

@developStorm developStorm requested a review from Copilot August 18, 2025 22:25
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces virtual scrolling to dramatically improve performance when rendering large numbers of badge icons. The virtualized grid renders only visible items on-demand, reducing DOM nodes and improving scroll performance, while maintaining responsive layout and adding graceful degradation for non-JavaScript users.

  • Implements virtual scrolling using virtual-scroller library to handle large datasets efficiently
  • Refactors search and ordering modules to work with callback-based architecture for better modularity
  • Adds progressive image loading with caching and placeholder loaders for better UX

Reviewed Changes

Copilot reviewed 21 out of 24 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
webpack.config.js Extracts icon data processing and injects as global ICONS_DATA constant
public/scripts/virtual-window.js New module implementing virtual scrolling with responsive grid computation
public/scripts/icons.js New module for creating badge elements with progressive image loading and caching
public/scripts/index.js Refactored main entry point to coordinate virtual window, search, and ordering
public/scripts/search.js Refactored to use callback pattern and extract badge filtering logic
public/scripts/ordering.js Refactored to support callbacks and expose sortBadges utility function
public/scripts/copy.js Updated to use event delegation on virtual list container
public/scripts/dom-utils.js Added getColumnsCount function for responsive grid calculations
public/scripts/utils.js Added groupIntoRows utility for virtual scroller row grouping
public/index.pug Updated template with loader, virtual list container, and noscript fallback
public/stylesheet.css Updated grid styles and added loader styles
package.json Added virtual-scroller@1.13.1 dependency
Various test files Added comprehensive tests for new modules and updated existing tests

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment thread public/scripts/icons.js Outdated
Comment thread public/scripts/icons.js Outdated
Comment thread public/scripts/virtual-window.js Outdated
Comment thread public/scripts/icons.js Outdated
@developStorm
Copy link
Copy Markdown
Owner

Thanks for the insights! Let's merge this once the Safari issue is resolved :D

@osabl
Copy link
Copy Markdown
Contributor Author

osabl commented Aug 19, 2025

Thanks so much for the quick reply and for agreeing to merge — that’s awesome news! 😉👍

I pushed a couple of small commits (style rollback + cleanup) and retested on iOS Safari — scrolling works fine on my side.

The scrollbar just moves very subtly because the page is so tall (3300+ virtual items). It might look stuck, but it’s actually working — same as in the previous version.

If I misunderstood and something else is happening, could you share a bit more detail? That would help me track it down.

@osabl
Copy link
Copy Markdown
Contributor Author

osabl commented Aug 26, 2025

@developStorm friendly ping) Could you take a look at the comment above?

@developStorm developStorm merged commit 4db33d1 into developStorm:master Aug 26, 2025
2 checks passed
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.

3 participants