Icon package structure
Background
Why can't we download only the icons we need?
The icons are published in a single npm package. It's not possible to download only part of an npm package. So any workaround would have to involve splitting icons into multiple packages.
Issues with deep imports
jest moduleNameMapper
Notes
- size 20 designed mainly for web, size 24 designed mainly for mobile
- why editing the SVGs to not scale line thickness didn't work
Questions
- Is major bumping all the icon packages an option?
- note, we'd also like to change the internal paths regardless, which could be considered a breaking change
- Do we have any components expected to need built-in icons besides size 20?
Possible solutions/workarounds
These are roughly in order of preference and/or viability, but the numbers are mainly there to facilitate easier discussion.
1. Separate packages for resizable and pixel-perfect icons
Preferably: @fluentui/react-icons
has resizable icons based on size 20, and another package (@fluentui/react-icons-sized?
name TBD) has pixel-perfect ones.
Downside is this would require a major bump of react-icons.
2. Custom subset package for fluent components
@fluentui/react-icons-fluent-subset
? (needs a better name)
- Probably defined within fluent-system-icons repo
- Published with other icon packages (stays in sync)
- Only includes and exports files for the specific icons used by
@fluentui/react-components
(using a manually-updated list of icons)
Example: if components only used Person20
and Dismiss20
, the package would contain only those icon files.
It would be consumed like this, for example in @fluentui/react-avatar
package.json
:
where icons are used:
Pros
- Easy to do immediately (could also be done as a temporary solution)
- No breaking changes
- Solves the immediate problem (icons package instantly shrinks to < 100 files)
Cons
- Manual step for fluent team members any time we want to use a new icon
- Doesn't help consumers who also want to use icons (they still have the penalty of downloading and parsing the giant package)
Make a subsetting tool (similar to what we have today for font icons) that lets people select only the icons used in their application.
The download would probably be formatted as an npm package, but to install it that way, the team that made the package would have to separately check it in somewhere (like as a package in their monorepo) and publish it.
Pros
- Most optimized for consuming repo download size and build time
Cons
- We don't have time for this (and it requires ongoing maintenance)
- Will require people to check their subsets into their own repos
- Subsets will quickly get outdated since they're not pulling directly from the original icon set on npm
- Higher barrier to entry to use icons
- people could potentially fall back to using the giant package, but they'd hit the original set of problems
4. Combine multiple icons into single file (reduce file count)
For each icon, put the components for each size, filled/outline variant, etc into one file to reduce file count. (These would still be exported as multiple independent components.) full example file
Rough example of a Search.tsx
icon file:
questions:
- would this even help with parse times?
Pros
- Reduces number of files to download
Cons
- Actually makes the bundle size worse with current implementation:
- The way the icons are currently written, webpack or rollup would NOT tree-shake out the unused icon variants from each file
- This is probably due to the
wrapIcon()
side effect
- Demo and details here
- Might not actually help much with parse times
- it depends on whether the true bottleneck is the file opens/reads or the parsing
5. Separate package for each size of icons
@fluentui/react-icons-20
, @fluentui/react-icons-24
, etc
Pros
Cons
- depending on how many sizes your app uses, you might end up back at the original problem
- not every icon is available at every size (unintuitive)
Split the icons into multiple packages, grouped by things that are conceptually related
Pros
- Might reduce number of files to download
Cons
- Not clear where to get a particular icon
- Harder to maintain