perf: bundle animate.css instead of loading it from a CDN - #270
Merged
Conversation
animate.css was pulled from jsdelivr as a render-blocking stylesheet. Bundling it removes that request for 5 KB gzipped. - add animate.css as a devDependency and @use it from styles.scss, the same way @docsearch/css and highlight.js styles are already imported - drop the CDN <link> from the head partial Imports the real published package rather than hand-copying the 9 keyframes the site uses, so there is no risk of the definitions drifting from upstream, and Renovate can keep it current. CSS bundle goes from 14967 to 20833 bytes gzipped. That is a good trade for removing a blocking third-party request, and it is why the whole file is imported rather than an extracted subset. font-awesome still loads from jsdelivr, so the origin stays on the critical path and its preconnect is still earned. Removing that one needs its 7 icons replaced with inline SVG. Part of #259 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
limonte
added a commit
that referenced
this pull request
Aug 5, 2026
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>
This was referenced Aug 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #259 — removes one of the two render-blocking third-party stylesheets.
Changes
animate.cssadded as a devDependency and@used fromstyles/styles.scss, the same way@docsearch/cssand highlight.js styles are already imported there<link>dropped frompartials/head.html4 files, +7 / −3.
Why import the package rather than extract the 9 keyframes
The issue suggested copying the keyframes the site actually uses into
styles.scss. I measured first: the full publishedanimate.min.cssis 5.2 KB gzipped. Against a 15 KB CSS bundle that's cheap enough that hand-copying isn't worth its downsides — extracted CSS silently drifts from upstream and has to be re-checked by hand on every update. Importing the real package means the definitions are upstream's, and Renovate keeps them current.Note the
source/files in the package can't be used directly: they carry unprefixed class names (.fadeInLeft), because theanimate__prefix is applied at the package's build step. Only the published file has the.animate__fadeInLeftselectors this site's markup depends on.Cost
CSS bundle: 14,967 → 20,833 bytes gzipped (+5.9 KB).
Good trade for eliminating a blocking third-party request — a cold connection costs far more than 5.9 KB of same-origin, already-cached-with-everything-else CSS.
Verification
animate.csslink is gone from all 23 built pages.fadeIn/fadeOut×Left/Right/Up/DownplusheadShake— each matched as an exact^\.animate__X \{rule, not a substring (animate__fadeInLeftwould otherwise matchanimate__fadeInLeftBig)..animate__animated,.animate__fasterand the:root { --animate-duration }custom property they depend on are all present..animate__headShakeis wired to a defined@keyframes headShake.bun run lintandbun run buildpass.Affected UI: the sidebar drawer (
src/utils/sidebar.tsx) and the sidebars-drawers and draw-attention recipes. Worth opening the sidebar once after deploy to confirm it still slides.Still open in #259
font-awesome 4 still loads from jsdelivr, so the origin remains on the critical path and its
preconnect(#267) is still earned. Removing it means replacing 7 icons —fa-bars,fa-arrow-left,fa-arrow-right,fa-external-link,fa-info-circle,fa-thumbs-up,fa-thumbs-down— with inline SVG. That's the larger half, and it's what finally takes jsdelivr off the critical path. Lazy-mounting Sandpack also remains.🤖 Generated with Claude Code