Skip to content

perf: replace Font Awesome with inline SVG icons - #271

Merged
limonte merged 1 commit into
mainfrom
seo-drop-font-awesome
Aug 5, 2026
Merged

perf: replace Font Awesome with inline SVG icons#271
limonte merged 1 commit into
mainfrom
seo-drop-font-awesome

Conversation

@limonte

@limonte limonte commented Aug 5, 2026

Copy link
Copy Markdown
Member

Part of #259. With animate.css bundled in #270, this removes the last third-party stylesheet from the critical path.

Font Awesome 4 is EOL (last release 2016) and was fetched from jsdelivr as a render-blocking stylesheet, which then pulled a whole icon webfont, to draw 3 glyphs of site chrome.

Changes

src/components/UiIcons.tsx (new) — IconBars, IconArrowLeft, IconExternalLink as inline SVG. Sized in em so they scale with the inherited font-size (.show-sidebar sets 1.8em, and the icon follows), and they inherit text colour via currentColor.

All three are decorative and aria-hidden — every call site either has adjacent text ("Back to Recipe Gallery", "jsDelivr CDN") or its own aria-label (the menu button). So nothing is lost for assistive tech.

.ui-icon in styles.scss nudges them onto the text baseline where the webfont glyphs sat (vertical-align: -0.125em).

Example code uses emoji instead. The three remaining icons live in src/examples/functions.ts, whose source is stringified and displayed verbatim as the documentation (see the minify finding on this issue). Inlining SVG path data there would wreck those snippets, so:

-confirmButtonText: `<i class="fa fa-thumbs-up"></i> Great!`
+confirmButtonText: `👍 Great!`
-Continue&nbsp;<i class="fa fa-arrow-right"></i>
+Continue&nbsp;→

Existing confirmButtonAriaLabel / cancelButtonAriaLabel values are unchanged, so the buttons keep their accessible names. This is the one visible content change in the PR — the thumbs-up/down and arrow in the "custom HTML" and T&C examples now render as emoji.

Removed the font-awesome <link> and, with it, the jsdelivr preconnect added in #267 — nothing loads from that origin any more, so the hint was dead weight.

Verification

  • 0 of 23 pages reference font-awesome or jsdelivr.
  • The only <link rel="stylesheet"> left in the head is same-origin: /assets/components-*.css.
  • Remaining external origins are analytics.limonte.dev (deferred), api.github.com / api.npmjs.org / ghbtns.com (after mount), and Algolia (on demand) — all dns-prefetch only, none blocking.
  • All three icon components are in the bundle with their path data intact, and .ui-icon is in the emitted CSS.
  • No fa fa- class remains in the JS bundle.
  • bun run lint and bun run build pass.

Left alone deliberately

recipe-gallery/validation-message-custom-icon-src.tsx:12 still uses fa-info-circle. That runs inside Sandpack, which only ever injects sweetalert2 plus per-recipe deps and never had Font Awesome — so that icon was already not rendering in its own preview. Pre-existing, unaffected by this change, and fixing it means rewriting a recipe whose subject is custom icons. Worth its own issue.

Worth a look after deploy

The mobile hamburger button, the "Back to Recipe Gallery" link, the two external-link icons, and the two affected examples on the homepage. This is verified by build output and CSS reasoning, not by rendering.

Still open in #259

Lazy-mounting Sandpack (1.17 MB / 317 KB gzipped on every recipe page).

🤖 Generated with Claude Code

Font Awesome 4 is EOL and was pulled from jsdelivr as a render-blocking
stylesheet, then downloaded a whole icon webfont, to draw 3 glyphs of
site chrome. With animate.css already bundled in #270, removing it takes
the last third-party stylesheet off the critical path.

- new src/components/UiIcons.tsx: IconBars, IconArrowLeft,
  IconExternalLink as inline SVG, sized in em so they scale with the
  inherited font-size and inherit text colour. All decorative, so
  aria-hidden - every call site has adjacent text or its own aria-label.
- .ui-icon in styles.scss nudges them onto the text baseline where the
  webfont glyphs sat.
- the example code in src/examples/functions.ts uses emoji instead:
  those snippets are displayed verbatim as documentation, so inlining
  SVG there would wreck them. Existing aria labels are unchanged.
- drop the font-awesome <link>, and with it the now-dead jsdelivr
  preconnect from #267.

No stylesheet is loaded from a third party any more. The remaining
external origins are all deferred, after-mount, or on-demand, so they
keep dns-prefetch only.

The stray fa-info-circle in validation-message-custom-icon-src.tsx is
left alone: it runs inside Sandpack, which only ever injects sweetalert2
and never had Font Awesome, so it was already not rendering. Pre-existing
and untouched by this change.

Part of #259

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@limonte
limonte merged commit 807ce49 into main Aug 5, 2026
1 check passed
@limonte
limonte deleted the seo-drop-font-awesome branch August 5, 2026 11:48
@limonte

limonte commented Aug 5, 2026

Copy link
Copy Markdown
Member Author

Correction: my justification for leaving fa-info-circle alone was wrong.

I wrote that the stray fa-info-circle in validation-message-custom-icon-src.tsx was already broken, because "Sandpack only ever injects sweetalert2 plus per-recipe deps and never had Font Awesome".

That is false. The recipe passes its own hidden /index.html:

recipe-gallery/validation-message-custom-icon.tsx
  '/index.html': { code: html, hidden: true }

recipe-gallery/validation-message-custom-icon-html.html
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/font-awesome@4/css/font-awesome.min.css" />

Sandpack.tsx only supplies a default /index.html when the recipe doesn't provide one, so this recipe's preview loads Font Awesome and the icon renders correctly. The recipe works, and its <p> says so explicitly: "In this example, we are using the Font Awesome icon instead of the default one."

Two things follow:

  1. Nothing to fix there. I started converting it to an inline SVG and reverted once I found this. That stylesheet loads inside the Sandpack iframe, so it never touched this site's critical path and there was no performance reason to change it — and the recipe deliberately demonstrates Font Awesome.

  2. There was a real leftover, elsewhere. Examples.tsx still passed codepenCssExternal="…font-awesome…" for the customHtml example whose icons this PR changed to emoji, so "Edit in CodePen" injected an unused stylesheet. Fixed in fix: drop the dead font-awesome CodePen stylesheet #275.

The site-side removal in this PR is unaffected: no font-awesome reference remains in the JS bundle or in any served page.

limonte added a commit that referenced this pull request Aug 5, 2026
#271 changed the customHtml example's buttons from fa-thumbs-up /
fa-thumbs-down to emoji, but left codepenCssExternal pointing at
font-awesome, so "Edit in CodePen" still injected a stylesheet nothing
used.

The other two codepenCssExternal values stay: animate.css is still
needed by the customAnimation example's pen, and bootstrap4-buttons.css
by the bootstrap example's.

No font-awesome reference remains in the JS bundle.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

1 participant