Draw the icons from the phosphor package that was already installed - #397
Merged
Conversation
react-icons was 82MB in node_modules to supply 129 icons, all but three of them from react-icons/pi — which is @phosphor-icons/react's artwork, repackaged. @gryt/ui already depends on the real one, so both were installed and only one was used. src/lib/icons.tsx exports the same 129 names over the package that was already there. The names are unchanged deliberately: react-icons puts the weight in the name and phosphor puts it in a prop, so renaming would have meant editing 291 call sites and getting the weight right at each. Here it is written once per icon, derived from the name it already had. It also keeps working where an icon is passed as a value rather than rendered, which the settings tabs do. GitHub and Ko-fi have no phosphor equivalent, so their paths are in src/lib/brandIcons.tsx — about 2KB, lifted from what react-icons drew. This costs about 0.4MB in dist/assets, which is real and worth saying: a phosphor icon carries all six weights in one component, so the bundle now contains duotone and thin variants nothing draws, where react-icons had a separate component per weight. Against 82MB off every checkout and every CI run it is a trade worth making, but it is a trade rather than a free win. Lint, typecheck and an Electron build all pass, and no react-icons import remains. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
sivert-io
added a commit
that referenced
this pull request
Sep 4, 2026
…ed (#398) generate-tray-icon.mjs imports three icons to render the tray glyphs, and it imported them from react-icons, which #397 deleted. The release died on "Generate app icons" before it built anything. I checked src/ for react-icons imports when removing it and did not check scripts/. Nothing else would have: lint and tsc do not cover scripts/*.mjs, and no local build runs icons:generate — it is a release step. Phosphor puts the weight in a prop rather than the name, and its components are forwardRef objects, so calling one the way react-icons' could be called throws. createElement instead. The rendered PNGs come out byte-identical, which is the check that matters: it is the same artwork either way. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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.
react-icons was 82 MB in node_modules to supply 129 icons, and 126 of them
came from
react-icons/pi— which is@phosphor-icons/react's artwork,repackaged.
@gryt/uialready depends on the real one, so both were installedand only one of them was used.
How
src/lib/icons.tsxexports the same 129 names over the package that was alreadythere. The names are unchanged on purpose. react-icons puts the weight in the
name (
PiGearSixFill) and phosphor puts it in a prop (<GearSix weight="fill">),so renaming would have meant editing 291 call sites and getting the weight right
at every one. Here it is written once per icon, derived mechanically from the
name it already had.
It also keeps working where an icon is passed as a value rather than rendered —
the settings tabs hold one per row, and a
weightprop at the call site is notavailable there.
GitHub and Ko-fi have no phosphor equivalent, so their paths live in
src/lib/brandIcons.tsx. Two paths, about 2 KB, lifted from what react-iconsdrew before it went.
The trade, which is not free
This costs about 0.4 MB in
dist/assets. A phosphor icon carries all sixweights inside one component, so the bundle now contains duotone and thin
variants nothing draws — I counted 120 duotone blocks in the built output.
react-icons had a separate component per weight, so it only ever shipped the one.
Against 82 MB off every checkout and every CI run, I think that is worth it, but
it is a trade and not the free win I described earlier. Roughly 100 KB in a
compressed installer, against 92 MB.
If you would rather not pay it, the alternative is vendoring the 129 single-weight
paths the way
brandIcons.tsxdoes — smallest bundle and smallest install, atthe cost of a generated 129-path file that no longer follows the package. Say the
word and I will swap it.
Verified
Lint, typecheck and an Electron build all pass. No
react-iconsimport remainsanywhere in
src. All 129 names mapped with none missing — 100 fill, 18 bold,11 regular.
Not verified: how they look. This is 79 files of icons and I have not put eyes on
a screen. The weight for each is derived from its old name, so a wrong one would
be a systematic mistake rather than a scattered one, but it is worth a look
around settings and the voice controls.
🤖 Generated with Claude Code