Skip to content

Decode SVG icon data urls in place instead of fetching them - #2411

Merged
kmcginnes merged 5 commits into
mainfrom
read-data-svg-icons-directly
Oct 14, 2026
Merged

kmcginnes merged 5 commits into
mainfrom
read-data-svg-icons-directly

Conversation

@kmcginnes

Copy link
Copy Markdown
Collaborator

Summary

Every stored icon is a lucide: reference or a base64 data: url, so the icon registry no longer needs a fetch, a retry cap or per-icon failure counts to resolve an SVG icon. It now decodes the url in place, and SVG icons resolve synchronously like rasters.

 request(sources)
   raster
     resolve now
   svg
-    fetch(url) → text → sanitizeSvg, async
-    on failure: count, retry up to 3 times
+    atob + TextDecoder (UTF-8) → sanitizeSvg, resolve now
+    on failure: remember it, never retry
   lucide
     import() → markup, async (unchanged)
  • The only failures left are deterministic: a payload that does not decode or sanitize, or an unknown Lucide name. The canvas requests on every render, so a failure is remembered rather than retried, which keeps it from being decoded and logged again on each render.
  • The one transient case left is a Lucide chunk that fails to load. It now stays blank on the canvas until the page reloads, where it previously got three tries. DOM surfaces render Lucide through DynamicIcon and are unaffected.
  • The "Unusable svg icon" warning now names the icon by the first 100 characters of its url, matching the unsupported-icon warning on load.
  • Test fixtures are base64 data: urls built by a new createSvgIconDataUrl helper instead of https://example.test urls behind a stubbed fetch.
  • useResolvedIcons is unchanged: its effect still triggers the Lucide import().

Evidence

Before: SVG icons resolved after an async fetch of their own data: url, and the registry tests depended on a stubbed fetch.

After: custom SVG icons render on the canvas with no fetch: one with non-ASCII text (airport), a width/height-only SVG with no viewBox (continent), and a Lucide icon (country).

Graph canvas showing a custom non-ASCII SVG icon on airport, a wide SVG with no viewBox on continent, and a Lucide anchor on country

Verified live: in Chrome against a Neptune air-routes database, I uploaded SVG icons with non-ASCII text, no viewBox, and invalid markup, then checked the graph canvas, legend, search results, style dialog preview, and schema view, including after a reload that restored the session. A window.fetch wrapper recorded no data: url fetches. The invalid icon showed no icon and logged one warning across repeated re-renders.

Merge Danger

Door: two-way

Stored data and the icon value format are unchanged, so reverting restores the old resolution path.

Impact: icons

A Lucide icon whose chunk fails to load stays blank on the canvas until reload instead of retrying.

Related

@kmcginnes kmcginnes left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Approved

Every stored icon is a lucide reference or a data url, so the icon
registry decodes SVG data urls synchronously and treats a failed
resolution as final, dropping the fetch and the three-attempt retry cap.

Closes #2354
@kmcginnes
kmcginnes force-pushed the read-data-svg-icons-directly branch from d75ed4d to e316926 Compare October 14, 2026 21:44
@kmcginnes
kmcginnes merged commit 72d84b3 into main Oct 14, 2026
4 checks passed
@kmcginnes
kmcginnes deleted the read-data-svg-icons-directly branch October 14, 2026 22:01
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.

Read data: SVG icons directly instead of fetching them in the icon registry

1 participant